コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB

インデックスの役割

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

インデックスの役割

このレッスンで分かること

  • 全表走査と索引参照の計算量の違い
  • インデックスがなぜ書き込みを遅くするのか
  • インデックスを貼る判断基準

インデックスの役割 とは

全件走査と索引参照の違いを計算量から把握する。本レッスンでは、インデックスの役割 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

インデックスがない世界

1000 万行のユーザーテーブルから WHERE email = 'alice@ex.com' を実行することを考えます。インデックスがなければ、DBMS は先頭行から順に 1 行ずつ email カラムを比較していきます。これを 全表走査 (Full Table Scan) と呼びます。

計算量は O(n) で、1000 万行なら最悪 1000 万回の比較が必要です。仮に 1 回 1 マイクロ秒としても 10 秒かかります。これでは Web アプリは破綻します。

インデックスがある世界

email カラムに インデックス を貼ると、DBMS は別途「email ソート済みの索引」を保持します。これを B-tree で持っていて、O(log n) で検索できます。

1000 万行なら log2(10000000) ≒ 23 で、23 回の比較で目的の行に辿り着けます。これは全表走査の 約 43 万倍 速いということです。

diagram (will load when visible)

インデックスの内部イメージ

インデックスは 「キー値 → 行の物理位置」のソート済み索引 です。本の巻末索引と同じ発想です。

emailrow_pointer
alice@ex.compage=12, slot=3
bob@ex.compage=87, slot=1
carol@ex.compage=44, slot=9

email で目的のキーを二分探索し、見つかったら row_pointer を辿ってテーブル本体の行を読み込みます。

インデックスのコスト

インデックスはタダではありません。次の 3 つのコストがあります。

1. ディスク容量 — インデックス自体がデータです。10 列に貼れば、テーブルとほぼ同サイズになることも。

2. 書き込みの遅延INSERT / UPDATE / DELETE のたびに、関連する全インデックスを更新する必要があります。インデックスが 10 個あれば書き込みは概ね 10 倍遅くなります。

3. メモリ消費 — 高頻度に使うインデックスはバッファプールに乗ります。メモリを食う。

インデックスは「読み取りを速くする代わりに、書き込みを遅くする」トレードオフ。

インデックスを貼る判断基準

次の条件のいずれかに当てはまるカラムは候補です。

  • WHERE 句で頻繁に使われる
  • JOIN の結合キーになる
  • ORDER BY / GROUP BY で使われる
  • 値の カーディナリティ(種類数) が高い

逆に、次のような列にインデックスを貼っても効果は薄いです。

  • 性別カラム(値が 2-3 種類しかない)
  • 削除フラグ
  • ほぼ NULL のカラム
  • 更新が極端に多いテーブル

カーディナリティが低い列は、インデックスを使うより全表走査のほうが速いこともあります。

複合インデックス

複数カラムを組み合わせた索引もあります。

SQL クエリ

CREATE INDEX idx_user_status_created ON orders (user_id, status, created_at);

これは「user_id でソート、同値内で status でソート、さらに created_at でソート」の索引です。

左端の原則 が重要です。(user_id, status, created_at) の複合インデックスは次のクエリに効きます。

  • WHERE user_id = ? — 効く
  • WHERE user_id = ? AND status = ? — 効く
  • WHERE user_id = ? AND status = ? AND created_at > ? — 効く
  • WHERE status = ?効かない(左端 user_id がない)
  • WHERE created_at > ?効かない

電話帳が「姓 → 名」でソートされていて、「名」だけで引けないのと同じです。

一意インデックス vs 通常インデックス

UNIQUE INDEX は値の重複を許さず、整合性制約も兼ねます。通常インデックスは検索高速化のみ。PRIMARY KEY は自動で UNIQUE INDEX になります。

クエリヒントとオプティマイザ

DBMS の クエリオプティマイザ が「どのインデックスを使うか」を決めます。複数貼ってあっても、最適なものを 1 つ選びます。意図と違うインデックスが選ばれることもあり、USE INDEXFORCE INDEX でヒントを与えることもできます(多用は禁物)。

やってみよう

  • CREATE INDEX の前後で、EXPLAIN の出力がどう変わるか比較する
  • SHOW INDEX FROM table_name で既存インデックスを確認する
  • 性別カラムにインデックスを貼ると本当に効くか試す(カーディナリティが低い場合の挙動)

よくある質問

Q. インデックスを貼ると遅くなる処理はありますか?

A. INSERT / UPDATE / DELETE は遅くなります。インデックス自体も更新が必要なため、書き込みが多いテーブルに大量のインデックスを貼ると書き込み性能が落ちます。読み取りと書き込みのバランスで判断し、不要なインデックスは削除しましょう。

Q. 複合インデックスは順番が大事ですか?

A. 順番が極めて重要です。(user_id, created_at) のインデックスは WHERE user_id = ? AND created_at > ? で効きますが、WHERE created_at > ? だけだと効きません。よく使う絞り込みカラムを先頭に置くのが定石です。

Q. インデックスが効いているか確認するには?

A. EXPLAIN(MySQL/PostgreSQL)または EXPLAIN ANALYZE で実行計画を見ます。type が ref / range / const なら使われていて、ALL は全件スキャン(インデックス未使用)です。意図と違うインデックスが使われている場合は USE INDEX で強制することもできます。

次のレッスン

次は B-tree の仕組み で、全件走査と索引参照の違いを計算量から把握する を学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. インデックスの役割 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. インデックスの役割 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン