编辑:另请参阅我的答案,主要区别是phpmyadmin添加的
LIMIT
,但我仍然不明白,phpmyadmin仍然比mysqli慢。
在我们的数据库 (+web) 服务器上,在 phpmyadmin 中执行查询与从 php (mysqli) 或直接在 mariadb 服务器上执行查询时,性能存在巨大的差异。 60 秒 vs 这个查询功能非常好:< 0.01 seconds!
SELECT * FROM `TitelDaggegevens`
WHERE `datum` > '2020-03-31' AND datum < '2020-05-02' AND `fondskosten` IS NULL
ORDER BY isbn;
但是,仅
在phpMyAdmin中,当我们将2020-05-02
更改为
2020-05-01
时,查询会变得非常慢。 SHOW PROCESSLIST
表明运行时查询主要是
Sending data
。以下mysql.rjweb.org/doc.php/index_cookbook_mysql#handler_counts
我做了以下查询系列:
FLUSH STATUS;
SELECT-query above with one of the two dates;
SHOW SESSION STATUS LIKE 'Handler%';
差异令人着迷。 (我在所有情况下都忽略了等于 0 的所有值)。并且随着时间的推移保持一致。
| how: | server/MySqli | phpMyAdmin
| date used in query: | 2020-05-02 | 2020-05-01 | 2020-05-02 | 2020-05-01
| records returned: | 6912 | 1 | 6912 | 1
| avg speed: | 0.27s | 0.00s | 0.52s | 60s (!)
| Variable_name | Value | Value | Value | Value
| Handler_icp_attempts | 213197 | 206286 | 213197 | 0
| Handler_icp_match | 6912 | 1 | 6912 | 0
| Handler_read_next | 6912 | 1 | 26651 | 11728896 (!)
| Handler_read_key | 1 | 1 | 151 | 4
| Handler_commit | 1 | 1 | 152 | 5
| Handler_read_first | 0 | 0 | 1 | 1
| Handler_read_rnd_next | 0 | 0 | 82 | 83
| Handler_read_rnd | 0 | 0 | 0 | 1
| Handler_tmp_write | 0 | 0 | 67 | 67
在所有情况下 EXPLAIN 结果都是相同
(phpmyadmin/mysqli/putty+mariadb)。
[select_type] => SIMPLE
[table] => TitelDaggegevens
[type] => range
[possible_keys] => fondskosten,Datum+isbn+fondskosten
[key] => Datum+isbn+fondskosten
[key_len] => 3
[ref] =>
[Extra] => Using index condition; Using filesort
唯一的区别在于行:
[rows] => 422796 for 2020-05-01
[rows] => 450432 for 2020-05-02
您能给我们任何
方向,我们应该在哪里寻找解决这个问题的方法吗?我们花了一周的时间来优化 mariadb 服务器(现在是最佳状态,除了 phpmyadmin)并将我们的一些问题缩小到下面的示例。我们经常使用 phpmyadmin,但对底层的内容(例如它如何连接到数据库)几乎没有经验。
关于索引/排序在慢速查询中,如果我们将
ORDER BY
从索引
isbn
字段更改为非索引字段,或者完全省略 ORDER BY
,一切都会再次恢复正常的闪电速度。将 ORDER BY
更改为主键 id
也会使其变慢,但仍然比索引 isbn
字段快 10 倍。我们*知道*我们可以通过更好的索引来解决这个特定的查询,我们已经准备好实现这一点。但是,我们想知道是什么原因导致 phpmyadmin 与 mysqli/directly 中的时间不同。
详情:
TitelDaggegevens 包含
表结构:< 11mln records, not even 3Gb, and has been OPTIMIZEd (rebuild)
CREATE TABLE `TitelDaggegevens` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`isbn` decimal(13,0) NOT NULL,
`datum` date NOT NULL,
`volgendeDatum` date DEFAULT NULL,
`prijs` decimal(8,2) DEFAULT NULL,
`prijsExclLaag` decimal(8,2) DEFAULT NULL,
`prijsExclHoog` decimal(8,2) DEFAULT NULL,
`stadiumDienstverlening` char(2) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL,
`stadiumLevenscyclus` char(1) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL,
`gewicht` double(7,3) DEFAULT NULL,
`volume` double(7,3) DEFAULT NULL,
`24uurs` tinyint(1) DEFAULT NULL,
`UitgeverCode` varchar(4) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL,
`imprintId` int(11) DEFAULT NULL,
`distributievormId` tinyint(4) DEFAULT NULL,
`boeksoort` char(1) COLLATE utf8mb4_unicode_520_ci DEFAULT NULL,
`publishingStatus` tinyint(4) DEFAULT NULL,
`productAvailability` tinyint(4) DEFAULT NULL,
`voorraadAlles` mediumint(8) unsigned DEFAULT NULL,
`voorraadBeschikbaar` mediumint(8) unsigned DEFAULT NULL,
`voorraadGeblokkeerdEigenaar` smallint(5) unsigned DEFAULT NULL,
`voorraadGeblokkeerdCB` smallint(5) unsigned DEFAULT NULL,
`voorraadGereserveerd` smallint(5) unsigned DEFAULT NULL,
`fondskosten` enum('depot leverbaar','depot onleverbaar','POD','BOV','eBoek','geen') COLLATE utf8mb4_unicode_520_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ISBN+datum` (`isbn`,`datum`) USING BTREE,
KEY `UitgeverCode` (`UitgeverCode`),
KEY `Imprint` (`imprintId`),
KEY `VolgendeDatum` (`volgendeDatum`),
KEY `Index op voorraad om maxima snel te vinden` (`isbn`,`voorraadAlles`) USING BTREE,
KEY `fondskosten` (`fondskosten`),
KEY `Datum+isbn+fondskosten` (`datum`,`isbn`,`fondskosten`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=16519430 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci
我们的虚拟网络+数据库+邮件服务器的配置:
MariaDB 10.4
InnoDB
CentOs7
phpMyAdmin 4.9.5
php 5.6
Apache
我们从虚拟网络服务器的默认设置中更改了一些重要的 mariadb 配置参数:
[mysqld]
innodb_buffer_pool_size=2G
innodb_buffer_pool_instances=4
innodb_flush_log_at_trx_commit=2
tmp_table_size=64M
max_heap_table_size=64M
join_buffer_size=4M
sort_buffer_size=8M
optimizer_search_depth=5
经过多次测试后发现,phpMyAdmin 添加的
LIMIT 0,25
是唯一导致极端延迟的原因。专家可以发现 mysqli/phpmyadmin 和直接在 mariadb 服务器上执行它没有任何区别。
有时,查询中非常小的差异(例如为只返回一条记录的查询添加 LIMIT)可能会导致查询花费 100.000 的时间,因为它将扫描整个索引,因为引擎会看到适合该查询的另一种策略。这是标准行为。我们已经找到了消除这个特定问题的索引,但现在我们也确信我们的数据库没有任何问题。我们不确定,因为这似乎是极端行为。所以,无事生非。
phpmyadmin 为查询添加了 LIMIT。这给出了主要的解释。我不敢相信这不是我们第一次尝试,我很尴尬。 但是,phpMyAdmin 和 mysqli 的速度差异还是很大,结果也还是不同(2020-05-01 在服务器上还是 mysqli 上):
+----------------------------+----------+
| Variable_name | Value |
+----------------------------+----------+
| Handler_commit | 1 |
| Handler_read_first | 1 |
| Handler_read_next | 11733306 |
| rest | 0 |
+----------------------------+----------+
limit
和2020-05-02的速度:都在0.17-0.2左右
limit
和 2020-05-01 加快速度:
php/mysqli:声称:3.5 秒,但页面加载大约 30 秒
putty/mariadb:声称也是 3.5 秒,但在大约 30 秒后显示结果
phpmyadmin:声称实时约 60 秒EXPLAIN 确实在 LIMIT 下发生了很大变化:
(第 1268 行有数据
+------+-------------+------------------+-------+------------------------------------+------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+------------------+-------+------------------------------------+------------+---------+------+------+-------------+
| 1 | SIMPLE | TitelDaggegevens | index | fondskosten,Datum+isbn+fondskosten | ISBN+datum | 9 | NULL | 1351 | Using where |
+------+-------------+------------------+-------+------------------------------------+------------+---------+------+------+-------------+
<20200501 and 1351 with datum<20200502)
SELECT * FROM `TitelDaggegevens`
WHERE `datum` BETWEEN '2020-03-31' AND '2020-05-02' AND `fondskosten` IS NULL
ORDER BY ISBN;
有没有办法从 phpmyadmin 获取
EXPLAIN
?如果是这样,这可能会提供另一个线索。
处理程序编号强烈暗示使用了不同的EXPLAIN
。
显然 phpmyadmin 修改了查询(至少通过添加LIMIT
)。我想知道它是否意外地扰乱了查询。您当时是否开启了Slowlog或General日志?要么应该有 SQL
as run。 将
(fondskosten)
上的索引替换为
INDEX(fondskosten, datum)
应该会提高性能。(“发送数据”一如既往,是引擎提供的无用信息。)
建议通过 mariadb.com 提交错误。