【実務・中級編】 並列クエリチューニングパラメータ – PostgreSQL

「ねえ、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を速くする唯一の近道だよ。

それじゃあ、今日はこの辺で。また何か詰まったら聞きに来てよ。応援してるよ!

コメント

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