【実務・中級編】 部分インデックス(Partial Indexes) – PostgreSQL

「全件インデックス」はもう古い?PostgreSQLの部分インデックスでDBを劇的に軽くする方法

やあ。最近、データベースのパフォーマンスチューニングで悩んでる?
「とりあえずカラムにインデックスを貼っておけば速くなるはず!」なんて考えて、テーブルの全行に対してインデックスを構築してないかな?

実はそれ、ストレージの無駄遣いなだけじゃなく、むしろクエリを遅くする原因になっているかもしれないんだ。

今日は、PostgreSQLの隠れた(いや、全然隠れてないけど、意外と使われていない)奥義、「部分インデックス(Partial Index)」について話そうと思う。これを知っているだけで、インデックスの肥大化を防ぎつつ、特定のクエリを爆速にできるぞ。

—

部分インデックスって何?

簡単に言えば、「テーブルの一部だけにインデックスを貼る」というテクニックだ。

通常、`CREATE INDEX` を実行すると、そのテーブルの全行に対してインデックスが作られるよね。でも、実際には「特定の条件を満たすレコードだけを頻繁に検索する」なんてケース、よくあるはずだ。

例えば、「未処理の注文だけを抽出したい」とか「論理削除されていないデータだけを一覧表示したい」とかね。こういう時、`WHERE` 句をインデックス定義に加えることで、PostgreSQLは条件に合致する行だけをインデックスに格納してくれる。

これが部分インデックスの正体だ。

具体的な使用例:インデックスを小さく保つ

たとえば、数千万行ある巨大な `orders` テーブルがあるとしよう。この中には `status` カラムがあって、`’pending’`(未処理)のデータだけを管理画面で頻繁に取得しているとする。

何も考えずにインデックスを貼るとこうなるよね。

— よくある全件インデックス
CREATE INDEX idx_orders_all ON orders (status);

これだと、処理済みのデータまでインデックスに入ってしまう。メモリ(shared_buffers)も食うし、更新のたびにインデックスの書き込みコストも発生する。

ここで部分インデックスの出番だ。

— 部分インデックスの定義
CREATE INDEX idx_orders_pending ON orders (created_at)
WHERE status = ‘pending’;

これだけで、`status = ‘pending’` であるレコードの `created_at` だけがインデックスされる。インデックスサイズは劇的に小さくなり、その分メモリにも乗りやすくなる。結果として、検索速度は体感できるレベルで向上するはずだ。

なぜこれが「現場の武器」になるのか?

実務で部分インデックスが重宝される理由は、主に3つある。

1. インデックスの肥大化を防ぐ
インデックスのサイズが小さくなれば、CPUキャッシュやメモリに載りやすくなる。B-treeの深さが浅くなれば、その分読み込み回数も減る。物理的な恩恵がデカいんだ。
2. 更新コストの削減
インデックスが増えるたびに、`INSERT` や `UPDATE` のたびにインデックスの再構築コストがかかる。部分インデックスなら、対象外の行が更新されてもインデックスを無視できるから、書き込み負荷が下がる。
3. NULLを無視できる(これが地味に最強)
「特定のカラムがNULLじゃないものだけ検索したい」というクエリ、よくあるよね。`WHERE column IS NOT NULL` で部分インデックスを作れば、NULLの行をインデックスから完全に除外できる。これだけでもインデックスサイズは数十分の一になることもあるよ。

注意点:魔法の杖ではない

もちろん、注意点もある。

  • クエリ側の WHERE 句と一致させる必要がある:インデックス定義に使った `WHERE` 条件と、実際に実行するクエリの `WHERE` 句が合致していないと、PostgreSQLはインデックスを使ってくれない。インデックスを貼ったのに「Seq Scan(全表走査)」になってたら、ここを確認してくれ。
  • 汎用的な検索には向かない:あくまで特定の条件に特化させるものだ。「たまに全件検索もするし、たまに特定条件でも検索する」という場合は、インデックスの使い分けを慎重に考える必要がある。

最後に:エンジニアとしての「引き出し」を増やそう

僕がジュニアエンジニアだった頃、「インデックスは貼れば貼るほど正義」だと思っていた時期がある。でも、大規模なシステムになればなるほど、「いかにインデックスを小さく、無駄なく作るか」という引き算の設計が重要になってくるんだ。

まずは、今のデータベースの「利用頻度の高い特定のWHERE句」を洗い出してみてくれ。そこが、部分インデックスを導入する最高のタイミングだよ。

「とりあえず全部インデックス」から卒業して、スマートなクエリチューニングを楽しんでいこうぜ!

また何か詰まったら、いつでも聞きに来てくれ。応援してるよ。

コメント

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