【问题标题】:MySQL - Why is phpMyAdmin extremely slow with this query that is super fast in php/mysqli?MySQL - 为什么 phpMyAdmin 对这个在 php/mysqli 中超快的查询非常慢?
【发布时间】:2020-09-10 08:11:19
【问题描述】:

编辑:另见我的答案,主要区别是phpmyadmin添加的LIMIT,但我还是不明白,phpmyadmin仍然比mysqli慢.

在我们的数据库 (+web) 服务器上,在 phpmyadmin 中进行查询与从 php (mysqli) 或直接在 mariadb 服务器上进行查询时,性能存在巨大差异。 60 秒 vs

这个查询功能很好:

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表示查询u主要是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 包含

表结构:

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

【问题讨论】:

    标签: mysql configuration phpmyadmin mariadb


    【解决方案1】:

    最大的不同是当然 phpmyadmin 在查询中添加了一个 LIMIT。这给出了主要的解释。我不敢相信这不是我们尝试的第一件事,我很尴尬。

    但是phpMyAdmin和mysqli的速度差距还是很大的,结果还是有区别的(2020-05-01 on server or 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 |
    +------+-------------+------------------+-------+------------------------------------+------------+---------+------+------+-------------+
    

    【讨论】:

    • 对不起。 SELECT * FROM TitelDaggegevens WHERE datum &gt; '2020-03-31' AND datum &lt; '2020-05-02' AND fondskosten IS NULL ORDER BY isbn LIMIT 0,25。查询加上限制。
    • 再次强调,这与优化查询无关。一个简单的索引就可以做到这一点。或者忽略 LIMIT。主要问题是(到目前为止):为什么查询报告需要 4 秒,而实际上需要 60 秒?
    • 我有日志文件(感谢提示),但它很长(也因为同时发生了其他事情)。在查询所需的那一分钟内,根本没有记录任何内容。所以那里没有帮助。主要是phpmyadmin需要在查询之后显示查询以及之前的一些准备工作的很多东西。 (因为我是从 phpmyadmin 运行的。)
    • 在快速查询和慢速查询之间的日志文件中也没有任何区别(除了在 phpmyadmin 中显示结果所需的东西)。基本上是200526 13:02:39 31186 Query SHOW WARNINGS 31186 Query SHOW SESSION VARIABLES LIKE 'FOREIGN_KEY_CHECKS' (3x this) 31186 Query SELECT DATABASE() 31186 Init DB admin_dvu 31186 Query SELECT * FROM TitelDaggegevens WHERE datum &gt; '2020-03-31' AND datum &lt; '2020-05-01' AND fondskosten IS NULL ORDER BY isbn LIMIT 0,25 200526 13:04:04 31186 Query SHOW WARNINGS
    • 我们很乐意(我尝试的第一件事)但我们必须首先检查/更新大约 1000 多个 php 页面到 php 7,因为我们仍在使用 php 5.6。
    【解决方案2】:

    考虑让 optimizer_search_depth=16 而不是 5 和 选择 * 从TitelDaggegevens 在“2020-03-31”和“2020-05-02”和fondskosten之间,datum 为空 按 isbn 排序;

    【讨论】:

    • 好电话。但是我们第一次遇到问题时是16,我们因为其他原因降低了它。 BETWEEN 没有任何区别(但它需要在问题查询中为 2020-04-30)。如果 mariadb 引擎有所作为,我会非常担心。 ;)
    • 再一个月的数据将在所需时间上有所不同。您是否考虑过在 phpmyadmin 中打开会话分析以获取有关正在使用哪些资源的详细信息?在您搜索所需时间的原因时再降一级。
    • 对于此类问题,请发布 QUERY 和 EXPLAIN(您的 QUERY)对 2020-05-01 的 phpmyadmin 测试最有帮助,因为它有大量的 handler_read_next 。
    • 我知道。这就是为什么我最初将它们放在问题和更新版本中(我自己的答案);)谢谢威尔逊,我们将研究分析。
    • 我预测分析会在“发送数据”之类的一些无用的事情上说 99%。
    【解决方案3】:

    除了您的所有提示之外,我们还对其进行了专家研究。

    经过多次测试,phpMyAdmin 添加的LIMIT 0,25 是唯一导致极度延迟的东西。专家可以发现mysqli/phpmyadmin和直接在mariadb服务器上执行没有区别。

    有时查询中的一个非常小的差异(例如为无论如何只返回一条记录的查询添加一个限制)可能会导致查询花费 100.000 的时间,因为它会扫描整个索引,因为引擎会看到另一种适合的策略那个查询。这是标准行为。

    我们已经找到了一个可以消除这个特定问题的索引,现在我们也确信我们的数据库没有任何问题。我们不确定的东西,因为它似乎是极端的行为。所以:无事生非。

    然而,我从这些经历中学到了很多东西。既来自我们的专家,也来自这个社区。我了解了 MySQL 诊断、日志记录、mariaDB 如何处理查询......对于每一个被证明不是问题的诊断,我学习了在表、索引或查询中要避免或努力的事情。

    谢谢大家,尤其是@Rick James、@Wilson Hauck 和@ExploitFate

    【讨论】:

    • 我发现MySQL倾向于忽略LIMIT。我想知道 MariaDB 是否将其考虑在内,但在您的“许多”示例中搞砸了。
    • MariaDB 只是根据许多因素采取了不同的方法,在这种情况下是一种非常不走运的方法。但是 LIMIT 和特定日期一起是它突然花费 100.000 倍的原因。
    【解决方案4】:

    (我来晚了。很高兴看到你已经“解决”了它。)

    你发现了一个奇怪的,并且很好地调查了。

    有没有办法从 phpmyadmin 获取EXPLAIN?如果是这样,那可能会提供另一个线索。

    处理程序编号强烈暗示使用了不同的EXPLAIN

    显然 phpmyadmin 修改了查询(至少通过添加LIMIT)。我想知道它是否不小心弄乱了查询。您当时是否打开了 Slowlog 或 General 日志?两者都应该让 SQL 运行

    (fondskosten) 上的索引替换为INDEX(fondskosten, datum) 应该会提高性能。

    (“发送数据”一如既往是引擎提供的无用信息。)

    建议向 mariadb.com 提交错误。

    【讨论】:

      猜你喜欢
      • 2013-07-09
      • 1970-01-01
      • 2015-09-02
      • 2011-04-08
      • 1970-01-01
      • 2016-12-17
      • 2015-11-21
      • 1970-01-01
      • 2012-07-12
      相关资源
      最近更新 更多