「場所」条件が何であれ、出現順に複数列インデックスを配置するのが最善であることを学びました。
あなたは学びました... 正確ではありません。
WHERE
オプティマイザは論理的に有効な方法で自由に条件を評価できるため、句内の出現順序は意味がありません。もちろん、式内の括弧や論理演算子 ( AND
、OR
など) を条件とします。
複数列インデックスの列の順序は重要です。なぜなら、左から右に、where 句で指定されていないインデックスで列が検出されるとすぐに、そのインデックスの右側に向かって何も使用できないためです。
3 つの列 (a、b、c) がインデックス化されていて、クエリが であるWHERE a = 1 AND c = 6
場合、オプティマイザーはそのインデックスの左端の「a」列の値のみを使用でき、「c」は使用できません。
その場合でも、インデックスを使用して a = 1 の行を検索し、識別されたすべての行をスキャンして c = 6 の行のみを検索することを選択する可能性があります。
複数列のインデックスを多次元配列として視覚化できます。最初の列 (a) に一致させる必要がある既知の値または範囲がなければ、2 番目の列 (b) の値は、「'a' のグループ」でソートされているため、無意味で順序付けられていないデータの寄せ集めになります。 ..すべての「a」を反復して一致する「b」値を見つけ、すべての「a、b」を反復して一致する「c」値を見つける必要があります。上記の例では、"b" 値は指定されていないため "anything" であるため、"c" 値の順序は無意味であり、クエリを最適化するためにアクセスできません (ただし、SELECT
リストが単一のインデックス内で使用可能な場合、オプティマイザーはテーブル全体をスキャンする代わりにインデックスをスキャンし、それを「カバーするインデックス」として扱います。これは通常、テーブル全体のスキャンよりも優れていますが、それでも最適ではありません)。
句に 2 つの列が含まれてWHERE
おり、どちらも個別にインデックスが作成されている場合、オプティマイザーはインデックス統計をチェックし、一致する可能性が最も低いものを使用しようとします... "a" と "c" にそれぞれ個別の値がある場合インデックスの統計は、"c" (カーディナリティが高い) には多くの値があるが、"a" (カーディナリティが低い) には少数の値しかないことを示しています。オプティマイザは通常、一致する行を見つけるために "c" のインデックスを使用します。これらの行をすべてスキャンして、要求された「a」の値を探します。
または、2 つのインデックスの結合を使用して、両方の条件を満たす行を正確に識別しようとする場合もあります。
これらの戦略はどちらも最適ではありませんが、完全なテーブルスキャンよりもはるかに優れているため、少なくとも、独立して検索可能なすべての列をインデックスの左端の列にすることをお勧めします...つまり、それ自体でクエリを実行でき、句に他の列がなくWHERE
、適切なサイズの結果セットを返す任意の列。結果セットのサイズが適切でない場合は、アプリケーションでユーザーが追加の属性を検索するように制限することができます。
より良いインデックスの場合、WHERE category = 'x' AND price < 100 AND price > 20
(価格、カテゴリ) ではなく (カテゴリ、価格) になりますが、これは句内の式の順序によるものではありませんWHERE
。これは、カテゴリは等値テストですが、価格は範囲であるためです。 WHERE price < 100 AND price > 20 AND category ='x'
は同等であり、(category,price) は引き続き適切なインデックスです。インデックスは最初の列で並べ替えられ、最初の列の各値内で、2 番目の列の値で並べ替えられ、次に各 (最初の,second) ペアは、3 番目の列の値で無限に並べ替えられます... (category,price) を使用すると、サーバーはカテゴリ = 'x' のすべての行に直接移動し、インデックス内のそのグループ内で、参照される行は既に価格でソートされているため、範囲を選択するだけで済みますインデックスのカテゴリ「x」内の価格。最適な。(price,category) インデックスでは、範囲内のすべての価格をチェックしてから、それらすべてのカテゴリ値をチェックする必要があります。インデックスは引き続き使用できますが、基準によっては、オプティマイザーがテーブル全体をスキャンすることを選択することもできます。
インデックス付けされていない句に 3 番目の基準を追加するWHERE
と、同じパスがたどられますが、サーバーは識別された行をスキャンして、インデックス付けされていない列の必要な値と一致するかどうかを調べます。繰り返しますが、最適ではありませんが、ビジネス ニーズによっては許容できる場合が多くあります。これは、この質問に対する正しい答えを決定する役割を果たします。
すべてのインデックスにはスペースとリソースが必要です。これは、挿入、更新、および削除のたびに、テーブルへの変更によって影響を受けるすべてのインデックスに対してサーバーが必要な変更をその時点で行う必要があるためです。
また、(a,b) または (a,b,c) などにインデックスがある場合、(a,. ..anything-else...) も (a) のインデックスとして機能します。
(MySQL 5.6 では/ /EXPLAIN SELECT
もサポートしています) を試し、 その出力を真に理解することは、インデックスがどのように機能するかを理解するための不可欠なツールです。MySQL 5.6 は もサポートしています。これにより、オプティマイザーがクエリをどのように理解したか、検討したさまざまなプラン、各プランの推定コスト、および特定のクエリの実行方法の決定に至った方法の詳細な出力が得られます。INSERT
UPDATE
DELETE
optimizer tracing