データベースのインデックス設計をレビューする
実際のクエリと突き合わせ、重複・無効・書き込みコストを指摘する
あなたはデータベース性能のレビュアーです。以下のテーブル定義、データ量、スロークエリをもとに、インデックスを一つずつ評価してください:1)各インデックスがどのクエリに使われるのか、WHERE / ORDER BY の該当部分を示す;2)最左プレフィックスが重複している索引、どのクエリにも使えない索引、索引が効かなくなる書き方(関数、暗黙の型変換、前方一致ワイルドカード)を指摘する;3)追加による書き込みとストレージへの影響を見積もる;4)最後に「残す/削除/追加」の三列で結論を出す。カラム名からクエリを推測しないでください。 [テーブル定義/インデックス/スロークエリ/行数]
使い方
まず「このインデックスはどの SQL のためにあるのか」を問います。答えが出ない索引は、たいてい容量を食い、書き込みを遅くしているだけです。
向いている場面
- いくつかのスロークエリが何週間も上位に居座り、その間に足したインデックスでも改善していません。
- 書き込みの多いテーブルにインデックスを足す前に、既存の索引で足りるかを確かめたいときです。
向いていない場面
- テーブルが数千行でメモリに収まるなら、インデックスの調整で結果は変わりません。
- 書き込みスループットがすでにボトルネックなら、索引を増やすと悪化します。改善にはなりません。
例
入力
CREATE TABLE orders (... user_id BIGINT, status VARCHAR(16), created_at DATETIME, ...); INDEX idx_user (user_id), INDEX idx_user_status (user_id,status), INDEX idx_status (status); SELECT * FROM orders WHERE user_id=? AND status='paid' ORDER BY created_at DESC LIMIT 20;
得られるもの
`idx_user` は `idx_user_status` の最左プレフィックスに完全に含まれるため削除できますが、`idx_user_status` では `created_at` の並び替えを満たせず filesort になるので、`(user_id, status, created_at)` を検討します。`idx_status` の選択性は status の値の種類に依存し、数種類しかないなら状態で一括走査するクエリがある場合にだけ効果があるため、削除前に他の SQL で使われていないか確認します。最後は「残す/削除/追加」で結論を出し、索引を 1 本増やすごとの書き込みとストレージのコストも示します。
よくある誤用
- `possible_keys` に出たことを、索引が使われた証拠と読むことです。`key` が NULL や走査行数がテーブル全体に近いなら、索引は効いていません。
- 遅いクエリのたびに索引を足すことです。書き込みの多い表では、重複した索引が挿入ごとに木を一つ増やします。
こう変えると効く
- 「索引ごとにディスク使用量と書き込み遅延への影響を見積もる」と加えると、レビューは「効くか」から「払う価値があるか」へ進みます。
- 「先にクエリ、後に索引」と求めることで、カラム名から索引を推測するよくある誤りを防げます。