次のようなクエリがあるとします。
SELECT *
FROM table_a
JOIN table_b USING (id)
WHERE table_b.column = 1
id
にインデックスとcolumn
にインデックスがありますが、多くの場合、このようなクエリの効率を向上させることができる両方の複合インデックスを追加します。私の質問は、インデックス内の列の順序に関するものです。試行錯誤の結果、DBMSは結合されたインデックスを最初に優先することも、WHERE
インデックスを最初に優先することもあります。
上記のクエリには、どのキーの順序が最適に機能するかを知るために遵守できる厳格な規則がありますか?
通常は、両方のインデックスを追加し、クエリでEXPLAIN
を実行して、どちらが望ましいかを確認してから、もう一方を削除します。しかし、このプロセスは、インデックスの順序の決定に関連するロジックをよりよく理解することで改善できるように感じます。
目安としては、複合インデックスの先頭列をできるだけ選択的にすることです。これを想像するための良い方法は、電話帳のアナロジーを使用することです。電話帳で誰かを見つける必要があり、2つのインデックスがあるとします。1つ目は姓、名です。 2番目はFirstName、LastNameです。 John Xylophoneという名前の人物を見つけるには、どのインデックスを使用しますか? Xylophoneエントリがほとんどないため、LastName、Firstnameインデックスを使用します。姓がXylophoneのJohnエントリをすべて探すよりも、はるかに短い時間で済みます。
したがって、id
の選択性が高く、column
の選択性が低い場合は、インデックスを(id, column)
にする必要がありますが、column
の選択性が高い場合は、そしてid
は選択性が低いため、おそらく(column, id)
として定義されたインデックスを使用することでメリットが得られます。
id
で必要な行数が大幅に減少したときに、x
の2つのテーブルを(column, id)
で結合すると、where column = x
のインデックスが使用される場合があります。参加しました。
for this query
_SELECT *
FROM table_a
JOIN table_b USING (id)
WHERE table_b.column = 1
_
最適な方法はそれを実行することです
WHERE
句はフィルタリングを提供するので、それを利用しましょう。つまり、_table_b
_ で始まるcolumn
にインデックスを作成します。 (後で合成するかどうかについて説明します。)したがって、オプティマイザーはそのインデックスを使用して_table_b
_の行を検索します。JOIN
から_table_a
_まで。 (_LEFT JOIN
_ではなくJOIN
が使用されていることに注意してください。_LEFT JOIN
_は別の話です。)table_a
_にアクセスするには、id
で始まるインデックスが必要です。 (注:USING(id)
は_table_a.id = table_b.id
_を意味します。)これまでのところ、
_b: INDEX(column)
a: INDEX(id) -- though it probably exists as PRIMARY KEY(id)
_
カバー?
2つのテーブルに他にどのような列があるかわかりません。列が非常に少ない場合は、「カバーする」インデックスを作成したくなるかもしれません。これは、SELECT
にall必要な列anywhereを含むインデックスです。利点は、インデックスのBTreeのみを参照し、データBTreeを操作する必要がないため、パフォーマンスがいくらか高速になることです。
_table_b
_の場合、INDEX(column, id)
と言いたくなるでしょう。これらの2つの列のみが存在する場合、それは(そして「カバーする」)良いでしょう。しかし、おそらくもっと列があります。したがって、おそらくINDEX(column)
を実行するだけの価値があります。
_table_a
_の場合、私はid
が_PRIMARY KEY
_(定義上、一意であり、インデックス)であると想定しています。したがって、それ以上は必要ありません。
ボトムライン:上記の2つの単一列インデックスを使用します。
そして、この例は「複合」インデックスについて何も例示していません。詳細については、
カーディナリティと範囲
カーディナリティとコンポジット
単一列のインデックス
インデックス作成クックブック
しかし、多くの場合、このようなクエリの効率を向上させることができる両方の複合インデックスを追加します...
より良い例
私が言ったように、あなたの例は質問を例示していません。それで、「いつ複合インデックスを使用する必要があるのか」と答えようとしますか?多くの場合があります(リンクを参照)。簡単なケースをあげましょう。
_WHERE x = 1
AND y > 2
_
関連する特性は次のとおりです。
x
とy
は同じテーブルにあります。 (2つのテーブルにまたがってインデックスを作成することはできません。)AND
が使用されます。 (OR
は最適化できません。)=
_を使用することです。 (両方が範囲である場合、複合は役に立ちません。)y
は「範囲」です(例:_y>2
_、_y LIKE 'm%'
_、_y BETWEEN ... AND ...
_)。一般的なルールは:
=
_列を最初に配置します(この例ではx
)y
)つまり、INDEX(x,y)
を注文する必要があります。
_WHERE x = 1 AND y = 2
_(両方の_=
_)の場合、notはINDEX(x,y)
またはINDEX(y,x)
のどちらを使用しているかに関係ありません。
もう1つのヒント:_ENGINE=InnoDB
_を使用すると、_PRIMARY KEY
_列が各セカンダリキーに暗黙的に追加されます。したがって、INDEX(column)
はINDEX(column, id)
と同じです。しかし、この事実はこの議論では役割を果たしていません。
私はここ(および他の場所)で他の回答に同意していないことに気付いていますが、私は自分の立場に立っています。
上記のクエリには、どのキーの順序が最適に機能するかを知るために遵守できる厳格な規則がありますか?
あなたが与えた例では、結合順序を自由に変更できる場合、最善の策は複合インデックスを持たないことです:
create table table_a(id integer, dummy_a integer); create index index_a on table_a(id); create table table_b(id integer, col integer, dummy_b integer); create index index_b on table_b(col);
explain select * from table_b join table_a using(id) where table_b.col=1;
id | select_type |テーブル|パーティション|タイプ|可能性のあるキー|キー| key_len | ref |行|フィルター済み|追加 -:| :------- :------ | :--------- | :--- | :------------ | :------ | :------ | :------------------------------------- | ---:| -------:| :---------- 1 |シンプル| table_b | null| ref | index_b | index_b | 5 | const | 1 | 100.00 | where の使用1 |シンプル| table_a | null| ref | index_a | index_a | 5 | fiddle_YRFDITQONPXNRMDBQSYV.table_b.id | 1 | 100.00 | null
db <> fiddle ---(ここ