「ねえ、PostgreSQLのクエリがやたら遅いからって、とりあえず`max_parallel_workers_per_gather`を適当に増やしてない?」
もし図星なら、ちょっと手を止めてこの記事を読んでほしい。
PostgreSQLの並列クエリは、魔法の杖じゃない。使い方を間違えると、システム全体のCPUを食いつぶして、他のクエリまで巻き添えにして遅延させる「諸刃の剣」なんだ。今日は、現場で本当に役立つ並列クエリのチューニングについて、教科書には載っていないような「実務の勘所」を話していくよ。
—
なぜ「並列化」が常に正解じゃないのか?
まず大前提として、並列クエリは「一つの重いクエリを、複数のCPUコアで分担して終わらせる」仕組みだ。でも、これには「調整コスト」がかかる。プロセスを立ち上げ、データを集め、結果をマージする。このオーバーヘッドが、短いクエリや、そもそもインデックスが効いていないクエリに対して発生すると、逆にシングルスレッドで動くより遅くなることだってある。
だから、「いつ並列化するか」をPostgreSQLに正しく教えてあげることが、チューニングの第一歩なんだ。
—
最重要パラメータの「本当の役割」
チューニングで触るべきパラメータはいくつかあるけれど、まずはこの3つを頭に叩き込んでおこう。
1. `min_parallel_table_scan_size`
これが一番の防波堤だ。
「このサイズより小さいテーブルなら、並列化する手間の方が無駄だからシングルでやろうぜ」という閾値。デフォルトは8MBだけど、データサイズが小さい環境なら、これを少し大きめに設定するだけで、無駄な並列化によるオーバーヘッドを減らせる。
2. `min_parallel_index_scan_size`
インデックススキャン版の閾値だ。これも同様。「インデックスを引くコストが小さいなら並列化するな」というサインを送る。
3. `max_parallel_workers_per_gather`
これがみんな大好きなやつだね。一つのクエリに対して、最大何個のワーカープロセスを割り当てるか。
初心者はこれをいきなり「8」とか「16」にしがちだけど、ちょっと待って。サーバーの総CPUコア数と、同時に動くクエリの数を考えてみてほしい。これに大きな値を入れすぎると、数本のクエリが走っただけでCPUがパンクして、DB全体が応答不能になる。まずは「2〜4」くらいから様子を見るのが、大人なエンジニアのやり方だよ。
—
具体的なチューニングの進め方:実験あるのみ
理屈をこねるより、`EXPLAIN ANALYZE`を叩くのが一番早い。
— チューニング前
EXPLAIN ANALYZE SELECT count() FROM orders WHERE status = ‘shipped’;
もしここで「Parallel Seq Scan」が表示されていて、かつ期待した速度が出ていないなら、まずは`cost`を疑おう。
実務で使えるワンポイントアドバイス
もし特定のテーブルだけ「いや、このテーブルは絶対に並列でスキャンしてほしいんだ!」という強情なやつがいるなら、テーブル単位で設定を変えるのがスマートだよ。
ALTER TABLE orders SET (parallel_workers = 4);
こうやって特定のテーブルにだけ並列度を指定することで、サーバー全体の設定をいじらずに、ピンポイントでパフォーマンスを最適化できる。これ、意外と知られていないテクニックだから覚えておいて。
—
現場で気をつけるべき「落とし穴」
最後に、これだけは守ってほしい。
- メモリの消費量に注意: `work_mem` はワーカープロセスごとに消費される。`max_parallel_workers_per_gather`を4にして、`work_mem`が100MBだと、一つのクエリで最大500MB(メイン+ワーカー4つ)のメモリを食うことになる。これを忘れてると、メモリ不足でOOM Killerに殺されるよ。
- ディスクI/Oの限界: CPUが余っていても、ディスクがSSDじゃなかったり、I/O待ちが激しい環境だと、並列化しても「待ち時間」が増えるだけ。まずは`iostat`や`sar`で、ボトルネックが本当にCPUにあるのか確認するのが先決だ。
—
結局、どうすればいいの?
チューニングに「魔法の数字」なんてない。まずは現状のクエリの実行計画を見て、どのコストが足を引っ張っているのかを見極めること。
もし迷ったら、まずはデフォルトの設定値をベースに、少しずつ`min_parallel__size`をいじって、無駄な並列化を排除することから始めてみて。それでダメなら、少しずつ`max_parallel_workers_per_gather`を上げる。
焦らず、一つずつ因果関係を確認する。これが、トラブルを最小限にしてDBを速くする唯一の近道だよ。
それじゃあ、今日はこの辺で。また何か詰まったら聞きに来てよ。応援してるよ!
コメント