チューニング
インデックスの罠 — 貼りすぎ・使われない・EXPLAIN 確認
インデックス過剰による書き込み劣化、未使用インデックスの検出、EXPLAIN 読解の基本。
インデックスの貼りすぎは禁物
インデックスは書き込みのたびに更新されます。INSERT / UPDATE / DELETE のコストはインデックス数に概ね比例して増えます。さらにディスク容量も消費し、バッファプールを圧迫します。
目安:
- 1 テーブルにつきインデックスは5〜7 本程度までを目処(ワークロード次第)
- 同じ列の組で複数のインデックスを作らない(先頭が同じ複合と単独は重複)
(a, b)の複合インデックスがあれば(a)単独は不要
使われていないインデックスを探して消す
RDBMS は「インデックスが使われた回数」を統計情報として持っています。定期的に確認し、使われていないインデックスは積極的に削除しましょう。残しておくと書き込みコストだけ払い続けることになります。
sql
-- PostgreSQL: 使用回数 0 のインデックス
SELECT schemaname, relname, indexrelname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0
ORDER BY pg_relation_size(indexrelid) DESC;
-- MySQL 8.0: 使われていないインデックス
SELECT * FROM sys.schema_unused_indexes;実行計画で答え合わせする
「インデックスが使われているはず」は思い込みになりがちです。EXPLAIN(PostgreSQL なら EXPLAIN ANALYZE)で実際の実行計画を確認するクセを付けましょう。
代表的な読み方:
Seq Scan(PostgreSQL) /ALL(MySQL) → フルスキャン。インデックスが使われていないIndex Scan/ref,range→ インデックスを使った検索Index Only Scan/Using index→ カバリング成功(テーブル本体を読んでいない)Bitmap Index Scan→ 複数条件を組み合わせてインデックスを利用
sql
EXPLAIN ANALYZE
SELECT * FROM orders
WHERE user_id = 42 AND created_at >= '2026-01-01';
-- 出力例 (PostgreSQL)
-- Index Scan using idx_orders_user_created on orders
-- Index Cond: (user_id = 42 AND created_at >= '2026-01-01')
-- (actual time=0.018..0.035 rows=12)