web-dev-qa-db-ja.com

インデックスが使用されている場合のタイプ「ALL」のMysqlExplainクエリ

私は以下のようにMysqlでクエリを実行しました:

EXPLAIN
SELECT *
FROM(
        SELECT *  # Select Number 2
        FROM post
        WHERE   parentid = 13
        ORDER BY time, id
        LIMIT 1, 10
    ) post13_childs
JOIN post post13_childs_childs
ON post13_childs_childs.parentid = post13_childs.id

結果は次のとおりです。

id |select_type  |table               |type |possible_keys  |key      |key_len  |ref              |rows    |Extra
1  |PRIMARY      |<derived2>          |ALL  | NULL          | NULL    |NULL     |NULL             |10      |
1  |PRIMARY      |post13_childs_childs|ref  |parentid       |parentid |9        |post13_childs.id |10      |Using where
2  |DERIVED      |post                |ALL  |parentid       |parentid |9        |                 |153153  |Using where; Using filesort

これは、インデックスparentidを使用したが、ALL153153のためにすべての行をスキャンしたことを意味します。インデックスがFull Scannigをしないのに役立たなかったのはなぜですか?

ただし、派生クエリを実行すると(#2を選択)単独以下のようになります:

Explain
SELECT * FROM post  
WHERE parentid=13
ORDER BY time , id
LIMIT 1,10

結果が望まれます:

id |select_type  |table  |type |possible_keys  |key      |key_len  |ref  |rows    |Extra
1  |SIMPLE       |post   |ref  |parentid       |parentid |9        |const|41      |Using where; Using filesort

編集:

テーブルpostには次のインデックスがあります。

  1. id(PRIMARY)
  2. 親ID
  3. 時間、ID(timeid)

合計行数-> 141280。
13の子の数(parentid=13)-> 41
11523の子の数-> 10119

(parent,time,id)のインデックスを追加すると、最初のクエリの問題は13-> 40行のexplin出力によって解決されます。type:ref
および11523-> 19538行の場合、type:ref !!!これは、最初の10行を制限しているときに、11423のすべての子行が検査されることを意味します。

17
ahoo

サブクエリ:

    SELECT *  # Select Number 2
    FROM post
    WHERE   parentid = 13
    ORDER BY time, id
    LIMIT 1, 10;

これは、3つの列に加えて、残りのすべての列について明示的に言及しています。3つのインデックスがあります。使用方法は次のとおりです。

  • id(PRIMARY)-このインデックスは役に立ちません。 order by句で言及されていますが、これは2番目の条件です
  • parentid-このインデックスは、where句を満たすために使用できます。ただし、正しいデータが取得された後は、明示的に並べ替える必要があります。
  • time、id(timeid)-このインデックスはソートに使用できますが、大きなものです。 MySQLはインデックスをスキャンして、すべてを正しい順序で取得できます。ただし、parentidの条件が満たされているかどうかを行ごとに確認する必要があります。

最適化が難しい理由を紹介するだけです。少量のデータがある場合(たとえば、テーブルが1ページまたは2ページに収まる場合)、全表スキャンとそれに続くソートでおそらく問題ありません。ほとんどのparentid値が13である場合、2番目のインデックスは最悪の場合である可能性があります。テーブルがメモリに収まらない場合、3番目は非常に遅くなります(ページスラッシングと呼ばれるもの)。

このサブクエリの正しいインデックスは、where句を満たし、順序付けが可能なインデックスです。そのインデックスはparentid, time, idです。これはカバーインデックスではありません(これらがテーブルのすべての列でない限り)。ただし、limit句があるため、実際の行へのヒット数は10に減るはずです。

完全なクエリの場合、parentidにインデックスが必要であることに注意してください。そして、幸いなことに、parentid, time, idのインデックスはそのようなインデックスとしてカウントされます。したがって、そのインデックスを削除できます。 time, idインデックスは、他のクエリで必要な場合を除いて、おそらく必要ありません。

また、クエリは、自分自身に「子供」がいる「子供」のみをフィルタリングしています。行が返されない可能性は十分にあります。本当にleft outer joinを意図していますか?

最後のコメントとして。このクエリは、実際のクエリを単純化したものだと思います。クエリは2つのテーブルからすべての列をプルしています-そしてそれらの2つのテーブルは同じです。つまり、同一のテーブルから重複する列名を取得します。列をより適切に定義するには、列エイリアスが必要です。

10
Gordon Linoff

どのインデックスにも助けられないORDERBYを実行すると、定期的にパフォーマンスが低下する可能性があります。内部クエリの場合、WHERE句とORDER BY句の両方がインデックスを利用できるように、(parentID、time、id)にカバーインデックスを設定します。 parentIDは結合のあとがきの基礎でもあるため、そこに移動して非常に高速にすることをお勧めします。

0
DRapp