【问题标题】:MySQL query randomly hangs on 'sending data' status?MySQL 查询随机挂在“发送数据”状态?
【发布时间】:2013-10-04 10:44:31
【问题描述】:

我使用 MySQL 5.5.25 服务器和 InnoDB 作为我的数据库。

由于 mysqld 进程大约一分钟,服务器的 CPU 经常以 100% 的速度工作。使用 SHOW PROCESSLIST:

Command | Time | State        | Info
Query   |  100 | Sending data | SELECT a.prefix, a...
Query   |  107 | Sending data | SELECT a.prefix, a...
Query   |   50 | Sending data | SELECT a.prefix, a...

有问题的查询是:

SELECT a.prefix, a.test_id, a.method_id, b.test_id
FROM a
LEFT JOIN b ON b.test_id = a.test_id
AND user_id = ?
AND year = ?

所有这些列都已编入索引,因此这不是问题。此外,当我在 phpMyAdmin 中运行查询(具有足够的 LIMIT)时,需要 0.05 秒才能完成。此外,令人沮丧的是,我发现自己无法重现此问题,即使同时执行此查询两次并发送垃圾邮件只会使我的 CPU 达到 40% 的峰值。

在查询前加上 EXPLAIN 会导致:

Id | select_type | table | type | possible_keys        | key     | key_len | ref          | rows | Extra
 1 | SIMPLE      | a     | ALL  | NULL                 | NULL    | NULL    | NULL         | 1169 | 
 1 | SIMPLE      | b     | ref  | user_id,year,test_id | test_id | 4       | db.a.test_id |   58 | 

除非我看不到我面前的东西,否则我正在寻找方法来发现如何调试此类问题。我确实已经记录了所有查询及其执行时间以及它们的值等。但是由于我无法重现它,所以我被卡住了。我应该怎么做才能弄清楚这个问题是关于什么的?

【问题讨论】:

  • 表的行数是多少。如果启用,则禁用查询缓存,然后重新生成。你有什么 CPU,线程数等。执行显示引擎 innodb 状态\G,寻找死锁年轻/非年轻,然后开始深入研究问题......
  • 感谢您的评论,如果这是一个答案而不是评论,我会接受它。

标签: mysql debugging innodb


【解决方案1】:

哇,感谢 Masood Alam 的评论,我找到并解决了问题。

使用SHOW ENGINE INNODB STATUS 对调试非常有帮助。

事实证明,对于 user_id 的某些值,数据库会以不同的方式处理事情,因此其行为不可预测并且无法重现问题。通过 status 命令,我能够复制并粘贴当前正在运行的确切查询。

这是EXPLAINuser_id 的特定值的结果:

Id | select_type | table | type         | possible_keys        | key          | key_len | ref  | rows | Extra
 1 | SIMPLE      | a     | ALL          | NULL                 | NULL         | NULL    | NULL |  841 | 
 1 | SIMPLE      | b     | index_merge  | user_id,year,test_id | user_id,year | 4,4     | NULL |   13 | Using intersect(user_id,year); Using where

接下来的问题是如何解释这种行为。但是,为我解决问题只需将查询更改为:

SELECT a.prefix, a.test_id, a.method_id, b.test_id
FROM a
LEFT JOIN b ON b.test_id = a.test_id
WHERE
b.id IS NULL
OR user_id = ?
AND year = ?

其中EXPLAIN 导致:

Id | select_type | table | type | possible_keys | key     | key_len | ref          | rows | Extra
 1 | SIMPLE      | a     | ALL  | NULL          | NULL    | NULL    | NULL         |  671 | 
 1 | SIMPLE      | b     | ref  | test_id       | test_id | 4       | db.a.test_id |   49 | Using where

现在我知道,在给定不同输入值的情况下,InnoDB 可以有不同的方法来执行查询。为什么?我还是不知道。

【讨论】:

    【解决方案2】:

    无论您使用哪种引擎,发送数据都是长时间运行查询的指示,因此非常糟糕。

    在您的情况下,在两种情况下都没有在表 a 上使用索引,您很幸运该表只有几百条记录。没有索引或 ALL(全表扫描)是完全避免的。请记住,当您的表中有数千甚至数百万条记录时,情况会有所不同。

    创建一个以查询为模型的索引以防万一。再次使用 EXPLAIN 查看引擎是否使用此索引。如果没有,您可以使用类似 USE INDEX(myindex) 或 FORCE INDEX (myindex) 的提示。结果应该是惊人的。

    否则,您的索引可能没有您想象的那么好。重申整个过程。

    但请记住,如果您更改查询,则使用此索引可能不再适用,因此您必须再次重申。

    【讨论】:

      猜你喜欢
      • 2021-09-11
      • 1970-01-01
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 2012-11-23
      • 2015-07-28
      • 2013-01-04
      • 2014-01-02
      相关资源
      最近更新 更多