第12回: 複合インデックスの順序 — 列の並びひとつで速度が激変する

章: 第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の読み方 を学びます。実行計画の各列が何を意味するのかを理解し、クエリ改善の根拠を数字で説明できるようになりましょう。

Related Articles