2016-10-26 3 views
0

非常に大きなデータセットで動作しているため、評価に時間がかかるSQLクエリがあります。私は、次を発見し、実行時間を改善しようとすると:空のセットを注文するとSQLクエリが非常に遅くなる

次のクエリを実行すると、MySQLサーバが(100secsまで)時間がかかる

SELECT some_data 
FROM table 
     INNER JOIN anothertable 
       ON (table.value = 
           anothertable.value) 
WHERE (table.parent = 56521 
     AND table.date >= 
      '2016-10-19 08:37:45.606947') 
ORDER BY table.date DESC 
LIMIT 1 

だから私はそれをソート一部だと推測しました

SELECT some_data 
FROM table 
     INNER JOIN anothertable 
       ON (table.value = 
           anothertable.value) 
WHERE (table.parent = 56521 
     AND table.date >= 
      '2016-10-19 08:37:45.606947') 
LIMIT 1 

を上記のクエリは、空のクエリセットに0.45秒とリードをとりますので、多くの実行時間がかかり、私は手動で実行の違いを見るために仕分けに削除クエリの。

WHERE節を評価する前に、私のクエリがWHOLEデータセットを注文したという結論に達しました。そのような動作を防ぐために、クエリをどのように作成する必要がありますか?この現象はなぜ現れますか?

これらは、低速と高速クエリのExplain表は以下のとおりです。

Slow 
+----+-------------+-------+------------+--------+------------------------------------------+------------------+---------+------------------------------+------+----------+-------------+ 
    | id | select_type | table | partitions | type | possible_keys       | key    | key_len | ref       | rows | filtered | Extra  | 
    +----+-------------+-------+------------+--------+------------------------------------------+------------------+---------+------------------------------+------+----------+-------------+ 
    | 1 | SIMPLE  | A  | NULL  | index | PRIMARY,D4b797d14e515242e7251754c57b7701 | date    | 5  | NULL       | 1325 |  0.08 | Using where | 
    | 1 | SIMPLE  | B  | NULL  | eq_ref | PRIMARY         | PRIMARY   | 4  | value      | 1 | 100.00 | NULL  | 
    +----+-------------+-------+------------+--------+------------------------------------------+------------------+---------+------------------------------+------+----------+-------------+ 

Fast: 
    +----+-------------+-------+------------+--------+------------------------------------------+----------------------------------+---------+------------------------------+------+----------+-------+ 
    | id | select_type | table | partitions | type | possible_keys       | key        | key_len | ref       | rows | filtered | Extra | 
    +----+-------------+-------+------------+--------+------------------------------------------+----------------------------------+---------+------------------------------+------+----------+-------+ 
    | 1 | SIMPLE  | A  | NULL  | ref | PRIMARY,D4b797d14e515242e7251754c57b7701 | D4b797d14e515242e7251754c57b7701 | 4  | const      | 5175 | 100.00 | NULL | 
    | 1 | SIMPLE  | B  | NULL  | eq_ref | PRIMARY         | PRIMARY       | 4  | value      | 1 | 100.00 | NULL | 
    +----+-------------+-------+------------+--------+------------------------------------------+----------------------------------+---------+------------------------------+------+----------+-------+ 
+1

「ORDER BY ...」を追加/削除すると、実行計画が変更される可能性があります。どのように違うのかを見るには、どちらの場合でも 'EXPLAIN SELECT ...'を試してみてください。さらに: 'table.parent'、' table.date'、 'table.value'や' anothertable.value'がインデックスに登録されていますか? – Sasha

+0

3つのフィールドのすべてが索引付けされます。 –

+0

もう1つの観察:このクエリを毎回実行すると、実行時間が長くなるわけではありません。いくつかは即座に実行され、いくつかはより多くの時間を取る - 同じクエリ、両親/日付の異なる値 –

答えて

1

MySQLがあなたの最初のクエリのdateにインデックスを使用しています。部分的にはwhereの条件(table.date >= '2016-10-19 08:37:45.606947')を評価することができ、それが適合すればテーブルから(比較的遅い)parentと読んで適合するかどうかを調べます。結果が見つかるとすぐに停止することができます(order bylimit 1のため)。

2番目のクエリでは、parent(長い名前のインデックス)のインデックスを使用し、適合する行を探して、テーブルからdate -partを読み取り、適合するかどうかを確認します。すべての行が正しいparent値(インデックスを使用して検出されたもの)でチェックされ、見つかったすべての行がfilesortを受け取り、最新の行が返されるまで続行する必要があります。

(MySQLはjoinもチェック/実行する必要がありますが、どちらのクエリでも同じです)。

あなたのdate条件に適合する行は、parentよりもはるかに多いので、比較的時間のかかるテーブル参照を行う必要があります。

この場合、データに応じて、dateのインデックスを介して確認された最初の行がすでにparentの条件を満たすため、実際にそこで停止する可能性があります。 parentのインデックスを使用する場合、MySQLはparentの値を持つすべての行をチェックしてからfilesortを実行しなければなりません。 MySQLはいくつかの統計データに基づいて決定した、それはリスクの価値があった。まあ、それは間違っていました。

次の操作を行うことができます

  • optimize table `table`(第2 tableがあなたのテーブル名である)あなたの統計情報を更新します。これは時には役立ちますが、統計データが非常に限られているため通常は役に立ちません。table(parent, date)はあなたにも、より速くなり、あなたの順不同よりを与える(joinの潜在的な影響を数えていない)必要がある複合インデックス:
  • あなたが知っているインデックスを使用する
  • 力MySQLは優れている(... FROM table force index (D4b797d14e515242e7251754c57b7701) inner join ...
  • は、クエリのための完全なインデックスを追加しますクエリを実行し、MySQLはそれを単独で使用します。
+0

あなたのお返事ありがとうございます。 3つ目のヒント(複合インデックス)が私の問題を解決したようです。私は複合インデックスを追加して以来、データベースは非常に高速です。どうもありがとうございました! –

関連する問題