【実務・中級編】 制約排除 (Constraint Exclusion) – PostgreSQL

PostgreSQLの「制約排除」を使いこなして、巨大テーブルの検索を爆速にする話

やあ。最近、ログテーブルや履歴データの肥大化に頭を抱えている現場をよく見かけるんだよね。「インデックスを貼っても検索が遅い」「VACUUMが追いつかない」なんて悲鳴を聞くたびに、僕は決まってこうアドバイスするんだ。

「パーティショニング、ちゃんと『制約排除(Constraint Exclusion)』を活用してる?」ってね。

今日は、PostgreSQLのクエリプランナーが裏でこっそり行っている、この魔法のような仕組みについて、実務的な視点で深掘りしてみよう。

—

制約排除(Constraint Exclusion)って何者?

簡単に言うと、「クエリの条件を見て、関係ないパーティション(子テーブル)は端から無視する」という最適化機能のことさ。

PostgreSQLは賢いから、各パーティションに `CHECK` 制約が付いていると、「ああ、このテーブルには2023年10月のデータしか入っていないんだな」と理解する。で、もしクエリが「2023年11月のデータをくれ」と言っていたら、そのテーブルには見向きもしないんだ。

これを使わない手はないよね。わざわざ全パーティションをスキャンして無駄なI/Oを発生させるなんて、エンジニアとしてちょっと勿体無いと思わない?

実践:どうやって設定するのか

まずは簡単な例を見てみよう。月次でデータを分割する「売上ログ」テーブルをイメージしてくれ。

— 親テーブル
CREATE TABLE sales_logs (
id serial,
log_date date NOT NULL,
amount int
) PARTITION BY RANGE (log_date);

— 子テーブル作成(ちゃんとCHECK制約的な役割を果たすのがポイント)
CREATE TABLE sales_logs_2023_10 PARTITION OF sales_logs
FOR VALUES FROM (‘2023-10-01’) TO (‘2023-11-01’);

CREATE TABLE sales_logs_2023_11 PARTITION OF sales_logs
FOR VALUES FROM (‘2023-11-01’) TO (‘2023-12-01’);

ここで重要なのは、`PARTITION BY` を使った宣言的パーティショニングを使っている場合、PostgreSQLが自動的に制約を管理してくれる点だ。昔ながらの継承テーブルを使っていた頃は、手動で `CHECK` 制約を書いていたけど、今はこれだけで十分。

クエリで確認してみよう

ここで、10月のデータを検索してみるよ。

EXPLAIN ANALYZE
SELECT FROM sales_logs WHERE log_date = ‘2023-10-15’;

`EXPLAIN` の結果を見てごらん。`Append` ノードの下に `sales_logs_2023_10` だけが登場して、`sales_logs_2023_11` は影も形もないはずだ。これが「制約排除」が効いている状態さ。

—

実務でハマらないための注意点

現場でよくあるミスを3つだけ共有しておくね。ここを押さえておかないと、せっかくの設計が台無しになるから注意してくれ。

1. データ型を一致させる
クエリの条件値とテーブルの列型が食い違っていると、暗黙の型変換が走って制約排除が効かなくなることがある。特に `date` 型と `timestamp` 型の混同には気をつけて。
2. 関数を噛ませない
`WHERE date_trunc(‘month’, log_date) = ‘2023-10-01’` みたいに、列に対して関数を適用すると、プランナーは「この列の範囲がどうなっているか」を判断できなくなる。`WHERE log_date >= ‘2023-10-01’ AND log_date < '2023-11-01'` のように、列をそのまま使う書き方を徹底しよう。 3. 設定パラメータを確認する
`constraint_exclusion` という設定パラメータがあるんだ。デフォルトは `partition` になっていればOK。もし `off` になっているような奇妙な環境に当たったら、速攻で疑ったほうがいい。

まとめ:賢い設計は、クエリを「読ませない」ことから始まる

データベースのパフォーマンスチューニングっていうと、インデックスをゴリゴリに追加しがちだけど、本当に優れたエンジニアは「いかに無駄なデータを走査しないか」という設計思想を持っている。

制約排除は、そのための強力な武器だ。もし今、君が巨大なテーブルと格闘しているなら、まずは `EXPLAIN` を取ってみて、不要なパーティションがスキャンされていないか確認してみてくれ。

それだけで、システムは驚くほど軽快に動くようになるはずだよ。

また何か詰まったら、いつでも聞きに来てくれ。一緒に最高にクールなデータベースを作ろうぜ。

コメント

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