データベースインデックス
検索クエリの高速化のためにデータベースが維持する補助的なデータ構造
データベースパフォーマンス
データベースインデックスとは
データベースインデックスは、テーブルの特定カラムに対する検索を高速化する補助的なデータ構造である。本の索引と同じ原理で、全ページを読む代わりに索引から目的のページを直接見つける。インデックスがなければ、DB はテーブル全体をスキャン (Full Table Scan) する必要がある。
インデックスの効果
-- インデックスなし: 100万行を全スキャン → 数秒
SELECT * FROM orders WHERE user_id = 'user-123';
-- user_id にインデックスあり: B-Tree で直接検索 → ミリ秒
CREATE INDEX idx_orders_user_id ON orders (user_id);
インデックスの種類
| 種類 | データ構造 | 用途 |
|---|---|---|
| B-Tree | 平衡木 | 等値検索、範囲検索 (デフォルト) |
| Hash | ハッシュテーブル | 等値検索のみ (範囲検索不可) |
| GIN | 転置インデックス | 全文検索、配列、JSONB |
| GiST | 汎用検索木 | 地理空間データ、範囲型 |
DynamoDB のインデックス
DynamoDB ではテーブル作成時にプライマリキー (パーティションキー + ソートキー) を定義し、追加のアクセスパターンには GSI (Global Secondary Index) を使う。
複合インデックス
複数カラムを組み合わせたインデックス。カラムの順序が重要だ。
-- (user_id, created_at) の複合インデックス
CREATE INDEX idx_orders_user_date ON orders (user_id, created_at);
-- ✅ 効く: user_id で検索
SELECT * FROM orders WHERE user_id = 'user-123';
-- ✅ 効く: user_id + created_at で検索
SELECT * FROM orders WHERE user_id = 'user-123' AND created_at > '2026-01-01';
-- ❌ 効かない: created_at だけで検索 (先頭カラムが条件にない)
SELECT * FROM orders WHERE created_at > '2026-01-01';
インデックスのトレードオフ
| メリット | デメリット |
|---|---|
| SELECT が高速化 | INSERT/UPDATE/DELETE が遅くなる |
| ソートが高速化 | ストレージを消費する |
| インデックスの選択を誤ると効果なし |
インデックスは「読み取りを速くする代わりに、書き込みを遅くする」トレードオフだ。書き込みが多いテーブルにインデックスを大量に作ると、書き込みパフォーマンスが低下する。
EXPLAIN で実行計画を確認
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 'user-123';
-- Index Scan using idx_orders_user_id on orders (cost=0.42..8.44 rows=1)
-- Execution Time: 0.05 ms
Seq Scan (全スキャン) が表示されたら、インデックスが使われていない。
現場での応用を知るには関連書籍も役立つ。