我正在使用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 = ?
所有这些列都是INDEXED,因此这不是问题。此外,当我在phpMyAdmin中运行查询(具有足够的LIMIT)时,完成需要0.05秒。另外,我发现自己无法重现这个问题是非常令人沮丧的,即使同时执行此查询两次并且发送垃圾邮件只会给我带来高达40%CPU的峰值。
使用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 |
除非我无法看清我面前的情况,否则我正在寻找方法来发现如何调试此类问题。我已经记录了所有查询的执行时间,以及它们的值等等。但由于我无法重现它,我被卡住了。我该怎么做才能弄清楚这个问题是什么?
答案 0 :(得分:8)
使用SHOW ENGINE INNODB STATUS
对调试非常有帮助。
事实证明,对于user_id
的某些值,数据库以不同的方式处理事物,因此其不可预测的行为并且无法重现问题。通过status命令,我能够复制并粘贴当前正在运行的确切查询。
这是EXPLAIN
的特定值user_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可以使用不同的方法来执行给定不同输入值的查询。为什么?我还是不知道。
答案 1 :(得分:0)
SENDING DATA表示长时间运行的查询,无论您使用哪种引擎,都非常糟糕。
在您的情况下,在两种情况下都没有在表a上使用索引,并且您很幸运该表只有几百条记录。完全避免避免使用索引或ALL(全表扫描)。请记住,当表中有成千上万条记录时,情况就不同了。
创建一个查询后建模的索引,以防万一。再次使用EXPLAIN来查看引擎是否使用此索引。如果没有,则可以使用诸如USE INDEX(myindex)或FORCE INDEX(myindex)之类的提示。结果应该是惊人的。
如果不是,则索引可能不如您想像的那样好。重复整个过程。
但是请记住,如果您更改查询,则使用该索引的方法可能不再适用,因此您必须再次重申。