2016-11-17 7 views
0

私はMySQL 5.6を使用しており、一部の非常に大きなテーブルではクエリのパフォーマンスに問題があります。具体的には、テーブル間の参照とin()条件の両方がある場合に、テーブルを適切にインデックスする方法がわかりません。外部キーと範囲を持つクエリのインデックスデザイン

簡易テーブルは以下の通りである(Cは小さなテーブルが約20行であるのに対し、AとBの両方が大きなテーブルで、すべてのテーブルであるのInnoDB)

(ID int型、日時を作成し、ヴァル・INT)

B(ID int型、A_ID INT、C_ID INT)

C(ID int型、ヴァル・INT)

は、問題のクエリは次のようになります。

Select a.id 
    from a 
    join b ON (a.id = b.a_id) 
    where a.created >= now() - interval 90 day 
     and a.val = 0 
     and b.c_id in (
     SELECT id 
      from c 
      where val = 1) 

私は(valを、作成、ID)としてのインデックスを作成しているし、素晴らしい作品(C_ID、A_ID)としてBに1があるとき " = '' c_idの条件(例えばc_id = 5)ですが、 'in()'条件では、Aのインデックスが使用されていない代わりにプライマリキーインデックスを使用しており、このクエリは永遠に。強制的に私のインデックスの使用はどちらか助けていないようです。

これをより良い方法で索引付けする方法や、このタイプのクエリのパフォーマンスを向上させる方法に関するヒントやアイデアはありますか?

答えて

1

IN (SELECT ...)は、JOINよりも効率が悪い。

Select a.id 
    from a 
    join b ON (a.id = b.a_id) 
    JOIN c ON b.c_id = c.id 
    where a.created >= now() - interval 90 day 
     and a.val = 0 
     and c.val = 1 

インデックス:

A: INDEX(val, created) -- in that order 
B: INDEX(a_id, c_id) -- in that order; "covering" 
C: Nothing new needed, assuming you have PRIMARY KEY(id) and InnoDB 

(編集)インデックスはテーブルがこの順序で行われますと仮定:Aは、B、Cのそれは、それが原因で... Aおそらく可能性が非常に高いですWHEREで最高の選択性を示します。明らかに、B、次にCが来る。したがって、Bのインデックスの私の注文。

AのPKが(id)であると仮定すると、INDEX(val, created)INDEX(val, created, id)と同じです(提案どおり)。 「派生」テーブル製剤、オプティマイザで

Bに移動し、その後、Cで開始し、最終的には、A「しなければならない」:

C: INDEX(val, id)  -- (again, `id` optional) 
B: INDEX(c_id, a_id) -- as you stated 
A: Given that it has `PRIMARY KEY(id)` and is InnoDB, no index is useful. 

ため、フィルタリングの無能のa.valにし、 a.createdは、私もこの製剤は私よりも遅くなることを予測する:

Select a.id 
    FROM (SELECT id FROM C WHERE val = 1) AS cx 
    JOIN B ON b.c_id = cx.id 
    JOIN A ON (a.id = b.a_id) 
    where a.created >= now() - interval 90 day 
     and a.val = 0 

Index Cookbook。 Bがたくさんのマッピングテーブルである場合、そのトピックに関するセクションに特に注意してください。

+0

非常に参考になりました。それはオプティマイザが同じページに常にではないようですが、どちらのインデックスを使用するかというと、これらの新しいインデックスではクエリがはるかに高速に実行されますが、明示的に使用する必要がありますか、 Aには年齢がかかる。 –

関連する問題