PostgreSQLのパラレルクエリと「仲良く」なるためのチューニング術
最近、後輩からこんな相談を受けました。「PostgreSQLでクエリが遅いからパラレルクエリを有効にしたいんだけど、どの値をいじればいいか分からなくて……」と。
わかる。すごくよくわかるよ。パラメータ設定画面を眺めていると、どれもこれも「性能が上がりそう」な魔法の数字に見えてくるよね。でも、ここを適当に設定すると、かえってシステム全体がガタガタになることもある。
今日は、PostgreSQLのパラレルクエリを実務レベルでどう制御していくか、教科書には書いていない「現場の肌感覚」を交えて話していくよ。
—
パラレルクエリの基本:心構え
PostgreSQLのパラレルクエリは、大きなテーブルをスキャンするときに、複数のワーカースレッド(プロセス)を立ち上げて「分担作業」させる機能だ。
でも、忘れないでほしいのは「並列化=コスト」だということ。プロセスを立ち上げるためのメモリやCPUのオーバーヘッドがあるから、小さなテーブルに並列処理を適用しても、逆に遅くなる。これを理解した上で、パラメータを調整していこう。
—
チューニングの主役たち
まずは、触るべきパラメータを整理するね。
1. `max_parallel_workers`:
システム全体で使える並列ワーカースレッドの最大数。これはサーバーのコア数に合わせて設定するのが基本だ。
2. `max_parallel_workers_per_gather`:
1つのクエリにつき、最大で何個のプロセスを動かすか。これが一番よく触る設定値だ。
3. `min_parallel_table_scan_size`:
「これくらいの大きさのテーブルなら、並列化しても元が取れるよね」という閾値。
—
実践:どう設定していくか?
僕が現場でよくやる手順はこんな感じだ。
1. まずは「土台」を決める
`max_parallel_workers` は、とりあえず「CPUのコア数」の半分〜同数程度を目安に設定する。ここを大きくしすぎると、クエリが走るたびにCPUが飽和して、OSのレスポンスまで悪くなるからね。
2. 「欲張り」すぎない値を設定する
`max_parallel_workers_per_gather` は、いきなり大きな値を入れないこと。まずは `2` か `4` あたりから始めるのが鉄則だ。
— 設定例:セッションごとに調整してテストしてみる
SET max_parallel_workers_per_gather = 4;
EXPLAIN ANALYZE SELECT FROM large_log_table WHERE status = ‘error’;
`EXPLAIN ANALYZE` を叩いてみて、`Workers Planned: 4` と出ているか確認してほしい。もし実行時間が短くなっても、CPU負荷が90%を超えて張り付くようなら、それは設定しすぎのサインだ。
3. 「小さなテーブル」の悲劇を防ぐ
デフォルトの `min_parallel_table_scan_size` は `8MB` だ。これが小さすぎると、インデックスが効かない小さなテーブルまで並列化しようとして、却って遅延を招くことがある。もし「あれ、意外と遅いな」と思ったら、ここを `64MB` や `128MB` に引き上げてみてほしい。
—
現場で遭遇する「落とし穴」
ここで、僕の苦い経験を一つ。
ある日、バッチ処理のクエリを速くしたくて、特定のクエリに対して `max_parallel_workers_per_gather` を強引に上げたら、DBサーバー全体のメモリが枯渇してOOM Killerにプロセスを殺されたことがあるんだ。
並列化は「メモリ」も食うってことを忘れないでほしい。
- `work_mem` × `max_parallel_workers_per_gather` = 1つのクエリが消費するメモリの目安
この計算を頭の片隅に置いておくこと。設定をいじるときは、必ず「今のサーバーの空きメモリで、この並列数は安全か?」を自問自答してほしい。
—
最後に:チューニングは「観測」から
結局のところ、パラメータに「銀の弾丸(万能な値)」はないんだ。
- `EXPLAIN ANALYZE` をとって、コストを眺める。
- `pg_stat_activity` で、実行中のクエリの負荷を確認する。
- 実際のアプリケーションの応答速度を計測する。
このサイクルを回すのが、結局一番の近道。最初は怖いかもしれないけれど、少しずつ数値をいじって、PostgreSQLがどう反応するかを楽しむくらいの余裕を持って向き合ってみて。
もし詰まったら、またいつでも聞きに来てよ。エンジニア同士、一緒に手を動かそう。
コメント