【実務・中級編】 複合インデックス (Composite Index) – PostgreSQL

「とりあえず全列にインデックス」は卒業しよう。PostgreSQLで複合インデックスを「正しく」設計する話

現場でパフォーマンスチューニングの相談に乗っていると、「クエリが遅いから、とりあえずWHERE句に入っているカラム全部にインデックスを貼りました!」というコードに遭遇することがよくあるんだ。

気持ちはわかるよ。でも、それだとデータベースはインデックスの海で溺れてしまう。特にPostgreSQLにおいて、複合インデックス(Composite Index)の設計は、ただ「列を並べる」だけじゃなくて、ある種の「職人芸」が求められる場所なんだ。

今日は、後輩エンジニアのみんなに、現場で恥をかかない、そして爆速なクエリを生み出すための「複合インデックスの極意」を伝授するよ。

—

1. なぜ「順番」がすべてなのか?

まず、基本のおさらいだ。B-treeインデックスの仕組みを思い出してほしい。データはインデックス内で「辞書順」にソートされて保存されているよね。

複合インデックス `(A, B)` を作った場合、PostgreSQLはまずAで並び替え、Aが同じならBで並び替える。つまり、「Aで絞り込まれた後、その中でBが並んでいる」という構造になるんだ。

ここで重要なのは、「左側の列(prefix)が指定されていないと、インデックスが極端に効きにくくなる」という特性だ。

— インデックス: (status, created_at)
SELECT FROM orders WHERE status = ‘shipped’; — 効く!
SELECT FROM orders WHERE created_at > ‘2023-01-01’; — 効かない(あるいはフルスキャンに近い)

後者のように、複合インデックスの「左側の柱」を無視してクエリを投げると、PostgreSQLはインデックスの恩恵をほとんど受けられない。これが「とりあえず列を並べただけ」のインデックスがゴミになる最大の理由さ。

—

2. 「カーディナリティ」という定石

じゃあ、どの列を左側に持ってくるべきか? 黄金ルールは「カーディナリティ(値の重複の少なさ)が高いものを左に置く」ことだ。

例えば、ユーザーの「性別(男女)」と「メールアドレス」でインデックスを貼るなら、どっちを左にすべきだと思う?

もちろん「メールアドレス」だ。性別で絞り込んでも半分しか減らないけど、メールアドレスなら一意に絞り込めるよね。絞り込みの効力が高いものを左に置くことで、PostgreSQLはインデックスをスキャンする範囲を劇的に狭められるんだ。

—

3. 実践!等価比較と範囲比較の「並び替えの魔法」

ここが一番の腕の見せ所だよ。WHERE句に「=(等価比較)」と「範囲指定(>, <, BETWEEN)」が混在する場合、インデックスの順序はこうしろ。 1. 等価比較のカラム(=)を先に並べる
2. 範囲比較のカラム(>, <)を最後に置く なぜか?
インデックスの中で、範囲指定をした瞬間に「そこから先はソート順がバラバラになるから、次の列のインデックスが役に立ちにくくなる」からなんだ。

NGな例

— インデックス: (created_at, status)
— created_atが範囲指定だから、statusの絞り込みがインデックス上で分断されてしまう
SELECT FROM logs WHERE created_at > ‘2023-10-01’ AND status = ‘error’;

GOODな例

— インデックス: (status, created_at)
— statusが等価なので、その範囲内でcreated_atが綺麗に並んでいる。これで最強の検索効率だ。
SELECT FROM logs WHERE status = ‘error’ AND created_at > ‘2023-10-01’;

この「等価を左に」というルールを守るだけで、クエリの実行計画(`EXPLAIN ANALYZE`)の「Index Scan」の精度が驚くほど変わるはずだよ。

—

4. 最後に:インデックスは「諸刃の剣」

最後に一つだけ忠告させてくれ。インデックスは読み取り(SELECT)を速くするけど、書き込み(INSERT/UPDATE/DELETE)のコストは確実に上がる。

複合インデックスを一つ増やすたびに、テーブルにデータが書き込まれるたび、そのインデックスも更新しなきゃいけないからね。

  • 本当にそのクエリは高頻度で実行されるのか?
  • そのインデックスは他のクエリでも再利用できないか?

この視点を忘れないでほしい。「速くするために作ったインデックスのせいで、全体の更新処理が遅くなってサービスが重くなる」なんていう本末転倒な状況だけは避けような。

—

どうだい? 複合インデックスは奥が深いけど、論理的に考えれば必ず最適解が見えてくる。次はぜひ、自分の担当しているプロジェクトの `EXPLAIN` を眺めて、「今のインデックス、本当にこの順番でベストかな?」って自問自答してみてほしい。

また現場で迷ったら、いつでも聞いてくれよな!

コメント

タイトルとURLをコピーしました