8

私は現在、次のようないくつかの (3) in 句を持つテーブルをクエリしようとしています:

 SELECT *
 FROM table
 WHERE
     a IN (2884,5320)
   AND 
     b IN ('a', 'b', 'c')
   AND 
     c IN (1, 2, 3)
   AND d='abcd'
   AND date BETWEEN 0 AND 1383177599

テーブルは次のようにインデックス付けされますindex(a, b, c, d, date)

ただし、クエリで Explain を実行すると、Explainer は使用する適切なインデックスがないことを示します。これは、私がFORCE INDEX.

上記INのいずれかを次のように変更する=

SELECT *
FROM table
WHERE
    a = 2884
  AND 
    b IN ('a', 'b', 'c')
  AND 
    c IN (1, 2, 3)
  AND d = 'abcd'
  AND date BETWEEN 0 AND 1383177599

MySQL では、強制的にインデックスを使用することができますが、それ以外の場合は別の非カバー インデックスを選択します。これは、どのINが に変更されたかに関係なく当てはまり=ます。

私の質問:

インデックス付きクエリに使用できる in 句の数に制限はありますか? ここで私が見逃している明らかなものはありますか?

テーブルについて知っておくべきことがいくつかあります:
9 GB、~8,000,000 行。これには、非常に大きくなる可能性がある 1 つのテキスト列 (JSON フィールド) が含まれていますが、この列は上記のクエリ対象の列のいずれでもありません。上記の in 句は大幅に大きくなる可能性があります (200 ~ 300 アイテム)

ありがとう!

EDIT:
これはクエリの説明の出力です(with FORCE INDEX1,"SIMPLE","table","ALL","correct_index",NULL,NULL,NULL,6977553,"Using where" 正しいインデックスは上記で説明したものです(index(a, b, c, d, date)

4

1 に答える 1

8

のような範囲述語のインデックスを介して複数の列が検索されることは期待できませんIN

複数列のインデックス (a、b、c、d、日付) がある場合でも、左端の列は等値述語( =) 用である必要があり、最大 1 つの列は範囲述語用にすることができます。インデックス内の後続の列は役に立ちません。

例:

WHERE a = 2884 AND b = 'b' AND c IN (1, 2, 3) AND d = 'abcd'

abは等価述語、はc範囲述語、dは別の等価述語です。

クエリで EXPLAIN を実行し、列と列が、インデックスの最初の 2 つの列のみを使用していることを示していることに注意してlenくださいref。の条件dは、最初の 3 つの列のインデックスによって見つかったすべての行を検索するという難しい方法で行われます。

           id: 1
  select_type: SIMPLE
        table: t
         type: ref
possible_keys: a
          key: a
      key_len: 7              <--- two columns' length
          ref: const,const    <--- only two values for index columns `a` and `b`
         rows: 4
        Extra: Using where; Using index

一方、等価述語に変更cすると、4 つの列すべてをインデックス検索に使用できます。

WHERE a = 2884 AND b = 'b' AND c = 2 AND d = 'abcd'

           id: 1
  select_type: SIMPLE
        table: t
         type: ref
possible_keys: a
          key: a
      key_len: 25                      <--- four columns' length
          ref: const,const,const,const <--- four values
         rows: 2
        Extra: Using where; Using index

これについては、プレゼンテーションHow to Design Indexes, Reallyで詳しく説明しています。


あなたのコメントについて:

コードを書き直さなくても、これを回避する方法はありますか?

インデックスの恩恵を受ける範囲述語は 1 つしか持てないという点は理解できました。WHERE 句に他の範囲述語を含めることはできますが、それらはインデックスから何のメリットも得られません。

インデックスを作成する 1 つの範囲式が検索を 99% まで絞り込むのに役立つ場合、それは勝利です。次に、一致した行に他の式を適用することは、許容できるコストです。

オプティマイザは、可能であれば最も効果的なインデックスを選択しようとしますが、これはインデックスの選択性に大きく影響されます。次に、クエリはインデックスを使用して検索を絞り込み、その検索に合格した行のサブセットのみが他の条件に対してテストされます。

クエリをもう一度見てください。

... WHERE
 a IN (2884,5320)
AND 
 b IN ('a', 'b', 'c')
AND 
 c IN (1, 2, 3)
AND d='abcd'
AND date BETWEEN 0 AND 1383177599

行の 1% のみが に一致することがわかっているとしますc IN (1,2,3)が、他の用語は平均して行の 20 ~ 40% 程度一致します。

等号述語のインデックスを作成できます。それで問題ありません。次に、他のすべての用語が範囲述語であるため、インデックス用に別の列を 1 つ選択します。最も選択的な列を選択します: c. したがって、最良のインデックスは(d, c)にあり、その順序でなければなりません。

WHERE 句で参照される列と、検索対象の特定の値について、さまざまな選択肢を持つアプリ内の他のクエリがある場合があります。そのため、列のセットが異なる別のインデックスが必要になる場合や、同じ列を異なる順序で並べる必要がある場合もあります。プレゼンテーションで述べたように、作成する必要があるインデックスは、最適化するクエリによって異なるため、複数のインデックスが必要になることは珍しくありません。

于 2013-10-30T22:00:42.453 に答える