mysql优化器

时间:2016-11-29 09:59:12

标签: mysql explain mysql-slow-query-log

我在Debian 8机器上使用mysql 5.5.52,有时我们的查询速度慢(> 3s),通常花费0.1s。我已经开始使用explain命令来查找正在发生的事情。

这是查询和解释信息

explain
SELECT
   `box`.`message_id` ID
 , `messages`.`tipo`
 , `messages`.`text`
 , TIME_TO_SEC(TIMEDIFF(NOW(), `messages`.`date`)) `date`
FROM (`box`)
INNER JOIN `messages` ON `messages`.`id` = `box`.`message_id`
WHERE `box`.`user_id` = '1010231' AND `box`.`deleted` = 0 
    AND `messages`.`deleted` = 0 
    AND `messages`.`date` + INTERVAL 10 MINUTE > NOW()
ORDER BY `messages`.`id` ASC LIMIT 100;


id| select_type| table  | type |  possible_keys   | key   | key_len| ref          | rows | Extra    
 1|SIMPLE      |box     |ref   |user_id,message_id|user_id|       4|const         | 2200 |Using where; Using temporary; Using filesort   
 1|SIMPLE      |messages|eq_ref|PRIMARY           |PRIMARY|       4|box.message_id|    1 |Using where

我知道临时表和filesort是一件坏事,我想问题是订单键不属于查询中的第一个表(框)并将其更改为box.message_id,解释信息是

  

id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra

     

1 SIMPLE框索引user_id,message_id message_id 4 443使用位置

     

1个SIMPLE消息eq_ref PRIMARY PRIMARY 4 box.message_id 1使用地点

它看起来更好,但我不明白为什么它使用message_id索引,最糟糕的是,现在查询需要1.5s而不是初始0.1s

编辑:

强制查询使用user_id索引,我得到与初始查询相同的结果(0.1s),但没有临时

explain
SELECT
   `box`.`message_id` ID
 , `messages`.`tipo`
 , `messages`.`text`
 , TIME_TO_SEC(TIMEDIFF(NOW(), `messages`.`date`)) `date`
FROM (`box` use index(user_id) )
INNER JOIN `messages` ON `messages`.`id` = `box`.`message_id`
WHERE `box`.`user_id` = '1010231' AND `box`.`deleted` = 0 
    AND `messages`.`deleted` = 0 
    AND `messages`.`date` + INTERVAL 10 MINUTE > NOW()
ORDER BY `box`.`message_id` ASC LIMIT 100;

id| select_type| table  | type |  possible_keys   | key   | key_len| ref          | rows | Extra    
 1|SIMPLE      |box     |ref   |user_id,message_id|user_id|       4|const         | 2200 |Using where; Using filesort   
 1|SIMPLE      |messages|eq_ref|PRIMARY           |PRIMARY|       4|box.message_id|    1 |Using where

我认为跳过临时是比初始查询更好的解决方案,下一步是检查组合索引为ysth推荐。

2 个答案:

答案 0 :(得分:0)

计算要比较的字段值不是一个好主意。然后你得到一个完整的表扫描。 MySQL必须先为每个ROW执行此操作才能检查条件。在恒定的条件下做它更好。然后MySQL可以使用索引(如果在此字段中有一个)

更改
AND messages.date + INTERVAL 10 MINUTE > NOW() 

AND messages.date  > NOW() - INTERVAL 10 MINUTE

答案 1 :(得分:0)

此处的临时和文件排序不好;它们是必需的,因为使用最佳索引(user_id)并不能自然地生成按照您要求的顺序排序的记录。

使用组合的user_id,message_id索引可能会做得更好,但这可能也会变得更糟。取决于您的确切数据。

如果您发现某些用户ID的查询时间较长或相同的用户ID有时会花费更长时间,则我不清楚。

更新:似乎将组合索引和更改顺序更改为box.user_id,box.message_id将解决您的问题,至少对于没有大量已删除邮件的用户而言。