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

「全部インデックスすればいい」はもう卒業。PostgreSQLの部分インデックスで、賢くパフォーマンスを稼ごう

こんにちは!今日もデータベースと格闘していますか?

PostgreSQLを触り始めてしばらく経つと、インデックスの魔力に取り憑かれる瞬間が来ますよね。「とりあえず検索条件に使うカラム全部にインデックスを貼っておけば速くなるだろう」……僕も駆け出しの頃はそう思っていました。

でも、インデックスって実は「ただの便利な道具」じゃないんです。書き込みのたびに更新コストがかかるし、ストレージも食う。いわば、「重たい荷物を背負いながら走る」ような側面もある。

そこで今日は、僕が現場で「これを知っていると一目置かれるよ」と後輩に必ず教える、部分インデックス(Partial Indexes)という必殺技について話そうと思います。

—

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

一言で言えば、「テーブル全体じゃなくて、条件に当てはまる行だけをインデックス化する」という手法です。

標準的なインデックスは、テーブル内のすべての行を対象にしますよね。でも、実際の現場のデータって、「アクティブなデータ」と「アーカイブ済みのデータ」が混在していることが多いはずです。

たとえば、`orders`(注文)テーブルで「未発送の注文」だけを頻繁に検索する場合、わざわざ「発送済み」の数百万件のレコードまでインデックスに含める必要はあるでしょうか?

実践:こんなケースで輝く

例えば、こんな注文管理システムがあるとしましょう。

CREATE TABLE orders (
id serial PRIMARY KEY,
status text, — ‘pending’, ‘shipped’, ‘cancelled’
user_id int,
created_at timestamp
);

ここで「未発送(pending)の注文だけを取得したい」というクエリが頻発しているとします。

普通のインデックス:

CREATE INDEX idx_orders_status ON orders(status);

これだと、テーブル全体をインデックス化します。`shipped`や`cancelled`のデータもインデックスに乗るので、インデックスサイズは肥大化し、更新時のオーバーヘッドも無視できません。

部分インデックス:

CREATE INDEX idx_orders_pending ON orders(status) WHERE status = ‘pending’;

こう書くと、PostgreSQLは「`status`が`pending`の行だけ」をインデックスに登録します。これ、めちゃくちゃ効率がいいんです。

—

なぜこれが「賢い」選択なのか?

実務で部分インデックスを使うと、こんな嬉しい恩恵があります。

1. 圧倒的な省スペース:
不要な行を含まないので、インデックスサイズが激減します。メモリ(shared_buffers)に載りやすくなるので、結果としてクエリは爆速になります。
2. 書き込み負荷の軽減:
`shipped`ステータスの行が更新されても、`idx_orders_pending`は何も関知しません。インデックスのメンテナンスコストが減る=書き込みが速くなる、というのはDB運用において最高のメリットですよね。
3. 統計情報の精度向上:
オプティマイザが「このインデックスを使えば対象行だけをダイレクトに狙える」と判断しやすくなり、実行計画が安定します。

—

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

もちろん、どんな時でも最強というわけではありません。

  • WHERE句の不一致:

インデックスを作った条件(`status = ‘pending’`)とクエリの検索条件が合致しないと、当然ながらインデックスは使われません。「たまに全件検索する」という用途には向いていないんです。

  • 「とりあえず」で作らない:

「この条件で本当に絞り込めるのか?」「将来的にこの条件は変わらないか?」という設計側の視点が不可欠です。

—

先輩からのアドバイス:現場で使いこなすコツ

僕がよくやるのは、「NULL排除」のパターンです。
「削除フラグ(`deleted_at`)」を持っているテーブルって多いですよね。`deleted_at IS NULL` のレコードだけをインデックス化するだけでも、ストレージの節約効果は絶大です。

CREATE INDEX idx_active_users ON users(email) WHERE deleted_at IS NULL;

こうしておけば、ログイン処理などで「まだ生きているユーザー」を検索する際、削除済みのユーザーを考慮せずに済みます。

—

まとめ

インデックス設計は、「どれだけ無駄を削ぎ落とせるか」の勝負です。

「全部に貼る」のは簡単ですが、それではデータベースエンジニアとしての腕は上がりません。「どのデータがビジネスの主役で、どのデータは脇役なのか」を理解し、主役のデータだけをインデックスという特等席に座らせてあげる。それが部分インデックスの哲学です。

ぜひ、皆さんの抱えている重たいテーブルのクエリを見てみてください。「あ、これ部分インデックスでいけるかも?」と思える箇所が、きっと一つはあるはずです。

それでは、良いデータベースライフを!また次回の記事でお会いしましょう。

コメント

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