20

クエリの 1 つが遅い理由とそれを修正する方法を理解しようとしていますが、結果に少し困惑しています。

orders約80列と775179行のテーブルがあり、次のリクエストを行っています:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC LIMIT 200

4.5秒で38行を返します

を削除するORDER BYと、素晴らしい改善が得られます:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL LIMIT 200

0.30 秒で 38 行

しかし、LIMITに触れずにを削除するORDER BYと、さらに良い結果が得られます:

SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC

0.10 秒で 38 行 (??)

なぜ私の LIMIT はそんなにお腹がすいているのですか?

もっと遠く行く

回答を送信する前にいくつかのことを試していましたが、インデックスがあることに気付いた後creation_date(これは ですdatetime)、それを削除し、最初のクエリは 0.10 秒で実行されるようになりました。何故ですか ?

編集

いいと思いますが、where の他の列部分にインデックスがあります。

mysql> explain SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC LIMIT 200;
+----+-------------+--------+-------+------------------------+---------------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys          | key        | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+------------------------+---------------+---------+------+------+-------------+
|  1 | SIMPLE      | orders | index | id_state_idx,id_mp_idx | creation_date | 5       | NULL | 1719 | Using where |
+----+-------------+--------+-------+------------------------+---------------+---------+------+------+-------------+

セットで 1 行 (0.00 秒)

mysql> explain SELECT * FROM orders WHERE id_state = 2 AND id_mp IS NOT NULL ORDER BY creation_date DESC;
+----+-------------+--------+-------+------------------------+-----------+---------+------+-------+----------------------------------------------------+
| id | select_type | table  | type  | possible_keys          | key       | key_len | ref  | rows  | Extra                                              |
+----+-------------+--------+-------+------------------------+-----------+---------+------+-------+----------------------------------------------------+
|  1 | SIMPLE      | orders | range | id_state_idx,id_mp_idx | id_mp_idx | 3       | NULL | 87502 | Using index condition; Using where; Using filesort |
+----+-------------+--------+-------+------------------------+-----------+---------+------+-------+----------------------------------------------------+
4

4 に答える 4

14

インデックスは必ずしもパフォーマンスを向上させるわけではありません。explain何が起こっているのかをよりよく理解するには、さまざまなクエリにを含めると役立ちます。

私の最善の推測は、句を満たすために使用できるインデックスがあるid_stateか、それさえあるということです。その場合、 を使用しない最初のクエリはこのインデックスを使用します。それはかなり速いはずです。インデックスがなくても、これにはテーブル内のページの順次スキャンが必要ですが、それでもかなり高速です。id_state, id_mpwhereorder byorders

次に、 にインデックスを追加するとcreation_date、MySQL は の代わりにそのインデックスを使用することを決定しますorder by。これには、インデックスの各行を読み取り、対応するデータ ページをフェッチしてwhere条件をチェックし、列を返す必要があります (一致する場合)。この読み取りは、「ページ」順ではなく、インデックスで指定された順序であるため、非常に非効率的です。ランダム読み取りは非常に非効率的です。

さらに悪いことに、 があっても、結果セット全体が必要なため、テーブル全体limitを読み取る必要があります。38 レコードの並べ替えを保存しましたが、非常に非効率的なクエリを作成しました。

ちなみに、ordersテーブルが使用可能なメモリに収まらない場合、この状況はさらに悪化します。次に、「スラッシング」と呼ばれる状態が発生し、新しいレコードごとに新しい I/O 読み取りが生成される傾向があります。そのため、1 ページに 100 件のレコードがある場合、そのページを 100 回読み取る必要がある場合があります。

にインデックスを設定することで、これらすべてのクエリをより高速に実行できますorders(id_state, id_mp, creation_date)where句は最初の 2 つの列をorder by使用し、最後の列を使用します。

于 2013-07-19T14:16:51.600 に答える