列が欠落しているにもかかわらず使用されているカバリングインデックス


8

MariaDB 10 / InnoDBを使用して、次のクエリがあります。

SELECT id, sender_id, receiver_id, thread_id, date_created, content 
FROM user_message 
WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

このクエリは、指定された条件に従ってメッセージをフェッチし、作成日順に並べ替えます。

をカバーするインデックスがあり(thread_id, date_created)ます。

EXPLAINを実行すると、正しいインデックスが使用され、クエリがインデックスにないステートメントの途中で列を使用しているにもかかわらず、「Using where」という出力が表示されます。「placeholder = x」には任意の値を使用でき、結果は同じです。

別の列を使用するように並べ替えを変更すると、EXPLAINは「whereの使用。filesortの使用」を正しく示します。

ひっかきの瞬間があります。誰かがこれに光を当ててくださいませんか?追加の列のためにカバリングインデックスを完全に使用できなかったため、追加のfilesortが必要になることを期待します。

回答:


8

ケースA
クエリ:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY some_column DESC 
LIMIT 20

インデックス:

(thread_id, date_created)

予定:

Index is used
Using Where
Using filesort

そこに問題はありませんよね?インデックスが(WHERE条件に部分的に一致するために)使用されている場合でも、結果を並べ替えるsome_column(インデックスにない)ソート操作が必要です。また、2番目の条件に一致する行のみを保持するために、追加のチェック(Whereを使用)も必要です。OK。


ケースB(質問)
クエリ:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

インデックス:

(thread_id, date_created)

予定:

Index is used
Using Where
-- no "Using filesort"

では、なぜここでソートが必要ないのですか?なぜなら、インデックスはクエリが望むようにソートするのに十分だからです。もちろんAND placeholder = FALSE、インデックスでカバーされていない追加の条件()の追加の問題があります。

わかりましたが、ここでは実際にソートは必要ありません。インデックスは、最初の条件(WHERE thread_id = 12345)に一致し、出力に必要な順序である結果を提供します。必要な唯一の追加のチェック-プランが行うこと-は、インデックスから提供された順序でテーブルから行を取得し、20件の一致が得られるまでこの2番目の条件をチェックすることです。これが、「**使用場所」の意味です。

最初の20行(非常に良好で高速)、最初の100行(まだ十分高速である可能性が高い)、または最初の1000000(おそらく非常に遅い)で20件の一致を取得するか、インデックスから一致するすべての行を読み取った後でもテーブル(大きなテーブルでは実際には非常に遅い)。それはすべてデータの分布に依存します。


ケースC(さらに良い計画)
クエリ:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

インデックス:

(placeholder, thread_id, date_created)

予定:

Index is used
-- no "Using Where"
-- no "Using filesort"

これで、インデックスは条件と順序の両方に一致します。計画は非常に単純です。最初の* 20一致をインデックスから取得し、対応する行をテーブルから読み取ります。余分なチェック( "Using Where"は不要)とソート( "Using Filesort"は不要)は不要です。

first *:インデックスを最後から逆方向に読み取るときの最初の20(私たちのようにORDER BY .. DESC)ですが、それは問題ではありません。Bツリーインデックスは、ほぼ同等のパフォーマンスで前方および後方に読み取ることができます。


7
  • インデックスを使用する「を示しているカバーインデックスは、」 - すべての列をどこかSELECTあるどこか 1インデックスインチ したがって、「カバーする」インデックスはありません。また、クエリのカバリングインデックスを作成することは現実的ではありません(言及されている列が多すぎます)。
  • 場所の使用 -ほとんどがノイズ。
  • filesortの使用 -クエリには並べ替えが必要ですが、RAMまたは一時テーブルにある可能性があります。そして、複数の種類があるかもしれません(例えばGROUP BY x ORDER BY b
  • これらのどちらでも、20行のみを見ることができます。他のインデックスでは、さらに多くの行、おそらくテーブル全体を操作する必要があります。

    INDEX(thread_id, placeholder, date_created)
    INDEX(placeholder, thread_id, date_created)
  • いいえ、複合インデックスのコンポーネントのカーディナリティは、インデックス内の列を順序付けるときに重要ではありません。

私のクックブックは、与えられた最適なインデックスを導き出す方法を説明していますSELECT


クックブックをありがとう-とても素敵なシート。
Tom
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.