章: 第3章: パフォーマンス最適化
インデックスを作ったのに、なぜか遅いまま?
「インデックスを追加したはずなのに、クエリが遅い」——そんな経験はありませんか?実は複合インデックスは、列の順序を間違えるとほとんど機能しません。正しい順序で設計するだけで、クエリが劇的に速くなるケースがあります。この回では複合インデックスの順序の考え方を整理していきます。
なぜ順序が重要なのか
複合インデックスはB-Treeの構造上、先頭列から順に使われるという特性があります。たとえば (user_id, status, created_at) というインデックスがあったとき、WHERE status = 'paid' だけでは先頭の user_id が使われないため、インデックスが有効活用されません。
問題は「インデックスを作った」という事実だけで安心してしまうことです。実際のWHERE句・ORDER BY句を分析し、先頭列から条件が使われる順に設計することが重要です。
良い設計・悪い設計の比較
| パターン | インデックス定義 | WHERE句 | インデックス利用 |
| 良い例 | (user_id, status, created_at) |
WHERE user_id=10 AND status='paid' ORDER BY created_at |
フル活用 |
| 悪い例 | (created_at, status, user_id) |
WHERE user_id=10 AND status='paid' ORDER BY created_at |
先頭列不一致でほぼ無効 |
| 良い例 | (status, created_at) |
WHERE status='paid' ORDER BY created_at |
範囲絞り込み後にソート可能 |
| 悪い例 | (created_at, status) |
WHERE status='paid' ORDER BY created_at |
ソート列が先頭で絞り込み効果なし |
チェックポイント: 実際のSQLのWHERE句とORDER BYを書き出し、左から順に「絞り込み効果が高い列」を並べられているか確認しましょう。EXPLAINの
key列にインデックス名が出ているかどうかが判断の基準です。
コードサンプル
-- 検索パターンに合わせる
CREATE INDEX idx_orders_user_status_created
ON orders (user_id, status, created_at);
EXPLAIN SELECT *
FROM orders
WHERE user_id = 10 AND status = 'paid'
ORDER BY created_at DESC;
まとめ & 次のステップ
- 複合インデックスは列の順序で効果が大きく変わります
- 先頭列がWHERE条件に含まれないと、インデックスはほぼ機能しません
- 実際のSQLパターンを先に整理し、絞り込み効果の高い列を先頭にします
- EXPLAINで
type: refまたはrangeになっているかを必ず確認しましょう - 変更前後でEXPLAINを比較し、改善を数値で記録しておくと判断材料になります
次回は EXPLAINの読み方 を学びます。実行計画の各列が何を意味するのかを理解し、クエリ改善の根拠を数字で説明できるようになりましょう。