【実務・中級編】 パーティションプルーニング – PostgreSQL

「全部スキャン」は卒業しよう。PostgreSQLのパーティションプルーニングを使いこなす話

やあ。最近、現場で「なんかクエリが遅いな」と思って実行計画(`EXPLAIN`)を覗いたら、何億行もある巨大テーブルを律儀にフルスキャンしていて頭を抱えた、なんて経験はないかな?

テーブルが肥大化してくると、インデックスだけではどうにもならない場面が出てくる。そんな時、僕たちが真っ先に検討すべき武器が「パーティションプルーニング(Partition Pruning)」だ。今日は、この仕組みをどうやって現場で活かすか、少し深掘りしてみよう。

—

パーティションプルーニングって何?

一言で言えば、「関係ない場所を見ない力」のことだね。

例えば、ログテーブルを月次でパーティション分割しているとする。ユーザーが「先月のログを見せて」と言った時、PostgreSQLが過去3年分の全パーティションをなめる必要なんてないはずだよね?

`WHERE`句の条件を見て、PostgreSQLのオプティマイザが「あ、この条件なら1月と2月のパーティションだけでいいや」と判断して、他のパーティションを最初からスキャン対象外にする。これがプルーニングの正体だ。

これを知っているかどうかで、パフォーマンスは文字通り「桁」が変わる。

—

1. 静的プルーニング:プラン作成時の「先読み」

まずは基本中の基本、静的プルーニングだ。これはクエリをコンパイルする段階(プランニング時)で、「どのパーティションが必要か」が確定する場合だね。

— 例えば、こんなクエリを投げるとする
EXPLAIN ANALYZE
SELECT FROM access_logs
WHERE log_date >= ‘2023-10-01’ AND log_date < '2023-11-01'; この時、`log_date`がパーティションキーになっていれば、実行計画にはこう出るはずだ。

  • `Subplans Removed: N`
  • `Append`の下に、該当するパーティションだけが表示される

もしここで「全パーティションにアクセスしている」ような計画が出ていたら、それはパーティションキーでフィルタリングできていない証拠だ。型変換(例えば`timestamp`の列に`text`を突っ込むなど)でインデックスが効かないのと同じで、型が合っていないとプルーニングは動かない。ここ、一番の落とし穴だから気をつけて。

—

2. 動的プルーニング:実行時に「判断」する賢さ

次に、もう少し高度な動的プルーニングの話をしよう。これはクエリを実行する直前まで、どのパーティションが必要か分からないケースだ。

例えば、こんなサブクエリを使った場合。

SELECT FROM access_logs
WHERE log_date = (SELECT MAX(created_at) FROM batch_jobs);

この場合、`batch_jobs`の中身を見て初めて「あ、昨日のパーティションだけでいいんだ」とわかるわけだよね。PostgreSQLは実行中にこの値を評価して、必要なパーティションだけを動的に選んでくれる。

ただ、この動的プルーニングは万能じゃない。あまりに複雑な条件を組むと、オプティマイザが諦めて「とりあえず全部見るか…」という残念な判断を下すこともある。そんな時は、素直にアプリケーション側で日付を計算して定数として渡してやるのが、結局一番速かったりするんだ。

—

実務で「プルーニングを効かせる」ための3つの心得

現場で設計する際、僕がいつも気をつけているのはこの3点だ。

1. パーティションキーをWHERE句に含めるのは「絶対」
どんなに設計が綺麗でも、クエリがキーを無視していたら意味がない。アプリ側のクエリ生成ロジックには、パーティションキーを意識した制約を必ず入れるようにしよう。
2. 型の一致を疑え
パーティションキーが `DATE` 型なのに、クエリで `文字列` として比較していないか? 暗黙の型変換が走ると、プルーニングが機能しなくなることがよくある。`EXPLAIN` を見たとき、`Filter` に条件が残っている場合は要注意だ。
3. あまり細かく分けすぎない
パーティションが多すぎると、逆にオプティマイザの負荷が高まって、計画作成時間(Planning Time)が無視できない長さになる。1テーブルあたり数百パーティションくらいまでが、管理とパフォーマンスのバランスが良いラインかな。

—

最後に

パーティションプルーニングは、魔法じゃない。データベースエンジニアが「データの持ち方」と「アクセスの仕方」を正しく設計してあげることで初めて発動する、いわば「誠実な最適化」なんだ。

今度、自分の担当しているプロジェクトで重いクエリがあったら、まずは `EXPLAIN` を叩いてみてほしい。「どのパーティションにアクセスしているか」を確認するだけで、劇的な改善のヒントが見つかるはずだよ。

もし何か詰まったら、いつでも相談してくれ。一緒にコードを読み解こう。それでは、良いパフォーマンスライフを!

コメント

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