「クエリが遅い……」と悩むジュニアエンジニアの横で、先輩がさらっとチューニングして解決する。そんなかっこいいエンジニアになるための第一歩、今日はPostgreSQLの「並列クエリ(Parallel Query)」について語ろうと思う。
PostgreSQLは優秀なデータベースだけど、デフォルト設定のままだと、実はその強力なCPUパワーを完全には使い切れていないことがあるんだ。今日は、どうすればPostgreSQLに「全開で働いてもらう」か、そのコツを伝授するよ。
—
そもそも「並列クエリ」って何をしているの?
簡単に言うと、「1つの作業を、複数の作業員(バックグラウンドワーカー)で手分けして終わらせる」仕組みだよ。
例えば、100万行ある巨大なテーブルから特定の条件でデータを集計する場合、普通は1つのCPUコアが上から順番に読み込んで計算するよね。でも、これだとCPUが余っていても作業は終わらない。並列クエリを使えば、テーブルを分割して複数のプロセスが同時にスキャンし、最後に結果を統合(Gather)してくれる。
結果、処理時間は劇的に短縮される。「なぜか集計クエリだけ異様に遅い」という時は、ここを疑うのが定石だ。
まずは設定を確認しよう
PostgreSQLが並列処理を行うかどうかは、いくつかの設定値で決まる。まずは現場で必ずチェックしてほしいのがこのパラメータだ。
— 現在の設定値を確認してみよう
SHOW max_parallel_workers_per_gather;
ここが `0` になっていると、そもそも並列処理がオフになっている。多くの環境では `2` や `4` に設定されていることが多いけれど、サーバーのスペックと相談して調整が必要だ。
チューニングの際の注意点
- `max_parallel_workers_per_gather`: 1つのクエリで最大何個のワーカーを使うか。あまり大きくしすぎると、CPUのコンテキストスイッチが頻発して逆に遅くなる。まずは `2`〜`4` くらいから様子を見るのが安全だよ。
- `min_parallel_table_scan_size`: 「これくらいのサイズ以上のテーブルなら並列処理しよう」という閾値。小さすぎるテーブルに並列処理を適用しても、プロセスを立ち上げるオーバーヘッドの方が高くついてしまうからね。
実際に試してみる(Explainで見よう)
並列クエリが効いているか確認するには、`EXPLAIN` を使うのが一番だ。
EXPLAIN ANALYZE
SELECT COUNT() FROM logs WHERE created_at > ‘2023-01-01’;
もし並列処理が走っていれば、実行計画の中に `Parallel Seq Scan` や `Gather` という言葉が出てくるはず。もしここが普通の `Seq Scan` になっていたら、PostgreSQLは「並列処理するより1人でやったほうが速い」と判断している証拠だ。
現場でよくある「落とし穴」
僕が後輩のコードレビューをしていてよくあるのが、「並列処理を期待していたのに走らない」というケース。これにはいくつか理由があるんだ。
1. 統計情報が古い:
`ANALYZE` を実行していないと、PostgreSQLはテーブルのサイズを正しく把握できない。結果、並列処理の恩恵を受けられないまま実行されることが多いんだ。「困ったらとりあえず `ANALYZE`」は現場の合言葉だね。
2. 書き込みを伴うクエリ:
残念ながら、データ変更(`UPDATE` や `DELETE`)は、現在のPostgreSQLのバージョンでも並列化されないことが多い。並列処理は「読み取り専用の重い処理」にこそ真価を発揮するんだ。
3. 関数呼び出し:
クエリ内で `STABLE` や `IMMUTABLE` ではない関数を使っていると、並列化が禁止されることがある。ここも意識しておくと、コードの質がグッと上がるよ。
まとめ:魔法の杖ではないと心得る
並列クエリは強力な武器だけど、魔法じゃない。
サーバーのCPUが常に高負荷な状態であれば、並列化することでさらに負荷をかけ、システム全体を共倒れさせるリスクもある。まずは「本当に重いクエリはどれか?」を `pg_stat_statements` などで特定し、そこに対してピンポイントでチューニングを施すこと。
「とりあえず並列度を上げれば速くなる」なんて安直な考えは捨てて、実行計画をじっくり観察する。その姿勢こそが、一流のデータベースエンジニアへの近道だよ。
それじゃ、また現場で困ったことがあったら聞きに来てくれ。君のクエリが爆速になるのを応援しているよ!
コメント