Postgres: よく絞る条件だけにパーシャルインデックスを張る
大半のクエリが同じ狭い条件で絞るなら、その条件を WHERE に入れたパーシャルインデックスにすると小さく速く、書き込みも軽くなる。
使う場面
ジョブキューや「未処理だけ」「有効な行だけ」を探すクエリが支配的なとき。全行に張ったインデックスは書き込みのたびに更新され、使わない行まで肥大化する。
やり方
sql
-- pending だけを created_at で並べるクエリ向け
CREATE INDEX ON jobs (created_at) WHERE status = 'pending';
-- クエリ側も同じ述語を書く(またはそれに含まれる条件)
SELECT * FROM jobs
WHERE status = 'pending'
ORDER BY created_at
LIMIT 50;- プランナはクエリの
WHEREがインデックス定義の述語と一致(または論理的に含まれる)ときだけ使う。 - 関連: ジョブキューのロック取りでは Postgres: FOR UPDATE SKIP LOCKED でテーブルをジョブキューにする でも
WHERE status = 'ready'のパーシャルインデックス例がある。外部キー列の通常インデックスは Postgres: 外部キーの列には自動でインデックスが付かない。子テーブル側に自分で張る。
注意点
- 述語に使う列を更新すると、インデックスへの出し入れが発生する(
pending→doneなど)。ステータス遷移が多い設計ではそのコストも見積もる。 WHERE status IN (...)や OR で述語が広がると使われないことがある。EXPLAIN で確認する。- 式インデックス(
lower(email)など)とは別枠。検索式そのものをインデックスにするなら Postgres: lower(email) で検索するなら式インデックスを張る。