9

foo(他の20の中で)列barを持つテーブルがbazありquux、インデックスがbazと にありquuxます。テーブルには最大 50 万行あります。

以下のクエリの速度が大きく異なるのはなぜですか? クエリ A は 0.3 秒、クエリ B は 28 秒かかります。

クエリ A

select baz from foo
    where bar = :bar
    and quux = (select quux from foo where bar = :bar order by quux desc limit 1)

説明

id  select_type table   type    possible_keys   key     key_len ref     rows    Extra
1   PRIMARY     foo     ref     quuxIdx         quuxIdx 9       const   2       "Using where"
2   SUBQUERY    foo     index   NULL            quuxIdx 9       NULL    1       "Using where"

クエリ B

select baz from foo
    where bar = :bar
    and quux = (select MAX(quux) from foo where bar = :bar)

説明

id  select_type table   type    possible_keys   key     key_len ref     rows    Extra
1   PRIMARY     foo     ref     quuxIdx         quuxIdx 9       const   2       "Using where"
2   SUBQUERY    foo     ALL     NULL            NULL    NULL    NULL    448060  "Using where"

MySQL 5.1.34 を使用しています。

4

1 に答える 1

9

にインデックスを追加する必要があります(bar, quux)

このインデックスがないと、MySQL はクエリを効率的に実行する方法がわからないため、さまざまな非効率的なクエリ プランから選択する必要があります。

最初の例では、インデックスをスキャンし、quux見つかった行ごとbarに、元のテーブルの対応する値を検索します。これは、各行をチェックするのに 2 倍の時間がかかりますが、正しい値を持つ行がbarスキャンの開始近くにあるため、停止することができます。これは、bar検索している値が頻繁に発生するためである可能性があるため、幸運になる可能性が非常に高くなります。その結果、一致を見つける前にほんの一握りの行を調べるだけでよく、各行をチェックするのに 2 倍の時間がかかりますが、少数の行しかチェックされないという事実により、全体的に大幅な節約になります。にインデックスがないためbar、MySQL は値:barが頻繁に発生することを事前に認識していないため、このクエリが高速になるかどうかを判断できません。

2 番目の例では、常にテーブル全体をスキャンする別の計画を使用しています。各行は、インデックスを使用せずにテーブルから直接読み取られます。これは、各行の読み取りは高速であることを意味しますが、行数が多いため、全体的には低速です。これに一致する行がない場合は:bar、より高速なクエリ プランになります。しかし、約 1% の行が の目的の値を持つ場合bar、上記のプランと比較して、このクエリ プランを使用すると (非常に) 約 100 倍遅くなります。にインデックスがないためbar、MySQL はこれを事前に知りません。

不足しているインデックスを追加するだけで、両方のクエリがはるかに高速になります。

于 2012-10-17T08:44:22.570 に答える