簡體   English   中英

MySQL優化器中的奇怪查詢

[英]Weird query in mysql optimizer

我在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

我知道臨時表和文件排序是一件壞事,並且我想問題是訂單鍵不屬於查詢(框)中的第一個表並將其更改為box.message_id,解釋信息是

id,select_type,表,類型,可能的鍵,鍵,key_len,引用,行,額外

1 SIMPLE框索引user_id,message_id,message_id 4443在何處使用

1條簡單消息eq_ref PRIMARY PRIMARY 4 box.message_id 1使用

看起來更好,但是我不明白為什么要使用message_id索引,更糟糕的是,現在查詢需要1.5秒而不是最初的0.1秒

編輯:

強制查詢使用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的建議檢查組合索引。

計算要比較的字段值不是一個好主意。 那么您將獲得一個全表掃描。 MySQL必須先檢查每個ROW,然后才能檢查條件。 最好在恆定條件下執行此操作。 然后MySQL可以使用索引(如果此字段中有一個)

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

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

臨時和文件排序在這里不錯; 它們是必需的,因為使用最佳索引(user_id)並不會自然產生按您要求的順序排序的記錄。

結合使用user_id和message_id索引可能會更好,但是最終結果也會更糟。 取決於您的確切數據。

我不清楚您是否看到更長的查詢某些用戶ID或相同的用戶ID有時需要更長的時間。

更新:似乎有一個組合的索引並按box.user_id,box.message_id更改順序可以解決您的問題,至少對於沒有大量已刪除郵件的用戶而言。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM