メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
カバリングインデックスとは、クエリが必要とするすべての列を含むインデックスです。まずインデックスの基本的な仕組みを理解しておくと役立ちます。MySQL のインデックスの仕組みでは、ここにも当てはまる B ツリー構造、キー長、および選択性のルールを説明しています。MySQL が実際のテーブルの行に触れずに、インデックスだけでクエリに答えられる場合、これをインデックスオンリースキャンと呼びます。大きなテーブルでは、これは単一クエリに対して使える最大級の最適化の 1 つです。

行の検索の仕組み(とそれが高コストな理由)

通常のインデックス検索は 2 つのステップからなります。
  1. MySQL はインデックスを検索して、どの行が一致するかを見つける
  2. 一致する各行について、MySQL はテーブルから完全な行を取得する(「行の検索」または「テーブルへの戻り検索」)
ステップ 2 が高コストな部分です。InnoDB のクラスタ化インデックスでは、テーブルのデータは主キーで物理的にソートされています。セカンダリインデックスで行を検索すると、主キーの値は散らばっているため、各行の検索は別のディスクページに対するランダム I/O になる可能性が高くなります。規模が大きくなると、これらのランダム読み取りがクエリ時間を支配します。 カバリングインデックスは、ステップ 2 を完全になくします。

EXPLAIN でカバリングインデックスを見分ける

EXPLAIN は、カバリングインデックスが使われているときにそれを教えてくれます。Extra: Using index を探してください。EXPLAIN の出力にまだ慣れていない場合は、MySQL の EXPLAIN の読み方で主要な列をすべて説明しています。
Using index — MySQL はインデックスだけを読みました。行の検索はありません。 次に、インデックスに含まれない列を追加します。
Extra が空になりました。MySQL はインデックスを使って行を見つけ、次に order_total を得るために完全な行を取得します。行の検索が戻ってきました。

カバリングインデックスの設計

目標は、クエリが触れるすべての列(WHERE、ORDER BY、GROUP BY、および SELECT リスト内の列)を含めることです。列の順序は、WHERE と ORDER BY のフィルタリングについては引き続き左端プレフィックスのルールに従います。
  • user_id が最初 — 等価フィルタ
  • created_at が 2 番目 — ソート列(インデックスはすでに並んでいるため、filesort は不要)
  • status が最後 — SELECT にだけ含まれ、フィルタリングにもソートにも使われない
SELECT の列が最後に来るのは、それらがどの行が見つかるか、どの順序になるかに影響しないためです。ただ同乗しているだけです。

カバリングインデックスが価値を持つ場面

よくある質問

カバリングインデックスは SELECT * に役立ちますか?

いいえ。インデックスがクエリをカバーできるのは、SELECT リストのすべての列を含む場合だけです。SELECT * はすべての列を選択するため、すべての列をインデックス化する必要があります。その時点で、テーブルをインデックスとして実質的に複製したことになり、有用ではありません。

それでもカバリングインデックスは SELECT * のクエリを速くできますか?

はい、部分的には。MySQL が行の検索を行わなければならない場合でも、インデックスは取得する行を絞り込みます。改善は WHERE のフィルタリングから来るもので、行の検索をなくすことから来るものではありません。

カバリングインデックスが役立つかどうかはどう判断しますか?

EXPLAIN を実行して Extra を確認します。Using index condition が表示されるか、何も表示されず(Using index がなく)、rows が大きい場合、カバリングインデックスが役立つかもしれません。EXPLAIN ANALYZE は実際の行数と推定の行数を表示するため、オプティマイザの選択を確認するのに役立ちます。

トラブルシューティング

関連項目