2016-11-29 15 views
0

私はDebian 8マシンでmysql 5.5.52を使用していますが、時には0.1sを費やす低速クエリ(> 3s)があります。私は何が起きているのかを見つけるためにexplainコマンドを使い始めました。mysqlオプティマイザの奇妙なクエリ

これは私が一時テーブルとfilesortレコードが悪いものであることを知っている、と私は問題は順序キーが最初のテーブルに属していないことであると仮定し、クエリと説明情報

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、テーブル、タイプ、possible_keys、キー、key_lenに、REF、行、エクストラ

1 SIMPLEボックス指数でありますユーザーID、

1つのSIMPLEメッセージを使用してPRIMARY PRIMARY 4 box.message_id 1でeq_ref使用MESSAGE_ID MESSAGE_ID 4 443どこ

それは今、最悪、MESSAGE_IDインデックスを使用して、そしてだなぜそれが良く見えますが、私は理解していませんクエリが1.5秒の代わりに、最初の0.1秒

編集取ります

はuser_idのインデックスを使用するクエリを強制的に、私は最初のクエリとしてではなく、一時的な

せずに同じ結果(0.1秒)を取得します
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が推奨するようにインデックスを組み合わせてチェックする方法です。

+0

2番目の説明が作成されたクエリを表示できますか? – ysth

+0

ああ、注文をmessage.idからbox.message_idに変更したということですか? – ysth

+0

'AND \' messages \ 'です。インターバル10分> NOW() ' - >' AND \ 'メッセージ\'。\ '日付\'> NOW() - インターバル10分。必要でないときに列を変換しないでください。 (これはこの場合問題ではないかもしれませんが、FYIだけです)。 – Pred

答えて

0

比較するフィールド値を計算することはお勧めできません。あなたはFULL TABLE SCANを取得します。 MySQLは条件をチェックする前に各ROWに対して実行する必要があります。一定の条件でそれを行う方が良いです。そして、MySQLはソートされている一時的な(もしこのフィールドにあり1)

の変化から

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

から

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

しかし、彼は完全なテーブルスキャンを取得していません。日付はここのインデックスではありません。 – ysth

+0

計算はインデックスでは機能しませんが、そのフィールド(日付)はインデックスに登録されておらず、変更されたクエリではオプティマイザがインデックスを使用していますが、間違っています(message_id) – OscarGz

+0

まあ、削除された、日付) ' - tmp + filesort +テーブルスキャンが消えます。 –

0

をインデックスを使用して、ファイルができないここに悪いです。最良の索引(user_id)を使用しても、要求された順序でソートされたレコードは自然に生成されないため、それらが必要です。

user_idとmessage_idの組み合わせのインデックスを作成する方が良いかもしれませんが、それも悪化する可能性があります。あなたの正確なデータに依存します。

特定のユーザーIDまたは同じユーザーIDに対してより長いクエリが表示されることがあるかどうかは不明です。

更新:削除されたメッセージが大量にないユーザーの場合、box.user_id、box.message_idにインデックスを統合して順序を変更すると、問題が解決する可能性があります。

+0

更新された回答。 – ysth

+0

遅いクエリは「ランダム」です。同じクエリを複数回実行すると、通常は正常に動作しますが、遅いクエリがあることがあります。クエリは問題ではありませんが、私はそれを最適化しようとしています。 – OscarGz

+0

なぜメッセージIDがmessage_idをインデックスとして使用しているのか分からないのですが、message.idのorder byオプティマイザはuser_idを使用しています。インデックスによる順序はインデックスの優先順位と同じです。 – OscarGz