Article
PostgreSQLの並列メンテナンス、ワーカー数を増やす前に見る制約
max_parallel_maintenance_workersは、1コマンドが起動できる並列ワーカー数の上限です。PostgreSQL 18のインデックス作成とVACUUMを例に、メモリ、処理単位、共有ワーカー枠から並列数が増えない理由を読み解きます。
Share
こはるの読みどころ
設定値、要求数、実際の起動数を分けて見るのがコツだよ。まずは遅い処理がどの段階で止まっているか、進捗とワーカーを一緒に見てみよう!

インデックス作成を早く終わらせたいとき、並列ワーカーの上限を引き上げるのは自然な選択です。ただ、その数字を増やしても、実際の処理に参加するワーカーが増えるとは限りません。
Christophe Pettus氏の設定解説「All Your GUCs in a Row」は、max_parallel_maintenance_workersがあくまで上限である点を取り上げています。調整したいのは、この設定値だけでなく、処理が並列化できる条件ですね。
PostgreSQL 18を対象に、ワーカーの「上限」「要求数」「起動数」を順に分けて考えます。どこが制約になっているかが分かれば、次に見直す設定や実行方法を絞れます。
1コマンドの上限と、サーバ全体のワーカー枠を分ける
max_parallel_maintenance_workersの既定値は2で、0なら対象のメンテナンス処理で並列ワーカーを使いません。値が2でも、サーバ全体のメンテナンスワーカーが合計2個に制限されるわけではなく、各コマンドにそれぞれ上限が適用されます。
実際の起動には、並列処理全体を制限するmax_parallel_workersと、そのワーカーを供給するmax_worker_processesの枠も必要です。空きが足りなければ、処理は要求より少ないワーカーで進みます。PostgreSQL 18のワーカープロセス設定で、この関係を確認できます。
つまり、単独実行で届かなかった上限と、同時実行で確保できなかったワーカーは、原因を分けて調べたいところです。
インデックス作成では、メモリが要求数を抑える
PostgreSQL 18で並列作成に対応する標準のインデックス方式はB-tree、GIN、BRINです。GINの対応はPostgreSQL 18のリリースノートに記載された追加点なので、古いバージョンへ同じ前提を持ち込まないようにします。
自動決定されるワーカー要求数には、テーブルの規模に加えてmaintenance_work_memも影響します。ワーカーごとに32MB、さらにリーダーにも32MBを残す条件があり、計算上の最低量は次のようになります。CREATE INDEXの並列作成仕様が根拠です。
| 要求したいワーカー数 | リーダーを含む参加数 | メモリ条件の最低量 |
|---|---|---|
| 1 | 2 | 64MB |
| 2 | 3 | 96MB |
| 4 | 5 | 160MB |
これは32MB ×(ワーカー数 + 1)という計算で、推奨設定値や起動保証ではありません。既定の64MBでは、通常の自動決定でメモリ条件を満たせるワーカーは最大1個です。
また、maintenance_work_memは並列メンテナンスのコマンド全体に対する予算です。ワーカーを増やすたびに同額を追加する仕組みではありません。メモリ予算の適用単位とCPU・I/Oの余裕を合わせて判断します。
テーブルのparallel_workersを明示すると、通常の要求数決定とメモリによる制限を迂回できます。ただし、通常の並列スキャンにも影響するため、インデックス作成だけの調整なら作業後のリセットまで含めて扱います。
VACUUMが並列化するのは、インデックス単位の処理
このメモリ計算を、そのままVACUUMに当てはめることはできません。通常のVACUUMが並列化するのはインデックスのvacuum・cleanupフェーズで、テーブル本体の走査を複数ワーカーで分割するものではないからです。
1つのインデックスを複数ワーカーに分けることもできません。並列処理に対応し、min_parallel_index_scan_sizeの条件を満たすインデックスが必要です。巨大なインデックスが1個だけのテーブルでは、上限を増やしても並列VACUUMのワーカーは起動しません。VACUUMのPARALLEL仕様が、この処理単位を定めています。
VACUUM (PARALLEL 4)も4個の起動を保証する指定ではありません。対象インデックスと設定上限の両方に制約され、ワーカーは対象フェーズの前後で起動・終了します。観測時にワーカーが見えない場合は、まずどのフェーズにいるかを見たいですね。
pg_restoreでは、ジョブ数とコマンド内の並列数が重なる
1コマンドの条件を整えたら、次は同時に何個走るかです。pg_restore -jは、データ読み込みやインデックス作成などを複数セッションで進めます。各ジョブが別接続を使うことは、pg_restoreのジョブ数オプションに明記されています。
たとえば3ジョブが同時にインデックスを作成し、それぞれ2ワーカーを要求するなら、要求は合計6ワーカーです。リーダーも含めると、その3コマンドに参加するプロセスは計算上9個になります。これは条件を置いた見積もりで、実測値ではありません。
同時実行が増えれば、コマンドごとのメモリ予算も重なります。ジョブ数だけ、あるいはワーカー数だけを最大化するより、両方を記録して復元時間とCPU・I/O負荷を比較するほうが、調整の効果を判断しやすくなります。
稼働ワーカーと進捗を見て、次の調整先を決める
最初に、処理を実行するセッションで有効な設定を記録します。次のSQLは設定を読み取るだけです。
-- セッションのメンテナンス設定と共有枠を記録する。
SHOW max_parallel_maintenance_workers;
SHOW maintenance_work_mem;
SHOW max_parallel_workers;
SHOW max_worker_processes;
インデックス作成中は、別の監視セッションからpg_stat_activityを見ます。backend_typeがparallel workerの行をleader_pidでまとめれば、リーダーごとの稼働数を観測できます。pg_stat_activityの列定義を使い、目的のコマンドのPIDと照合します。全セッションの詳細を見る場合は、監視用ロールの権限も必要です。
さらに、インデックス作成の進捗ビューにあるcommandとphaseを合わせます。waiting for writers before buildのような待機フェーズなら、まず待機相手を調べる場面です。1回の観測でワーカーが見えないことだけから、処理全体が直列だったとは判断できません。
上限まで使っていないときは、要求を小さくする条件と、起動を妨げる共有枠を切り分けます。十分に起動していても時間が縮まらなければ、CPUやストレージ側の余裕を見直します。並列数を大きくすることより、処理が進まない理由に合った調整を選べることが、この設定を理解する実務上の利点です。
出典
- Title: Christophe Pettus: All Your GUCs in a Row: max_parallel_maintenance_workers
- URL: https://postgr.es/p/9v7
Share
Related Articles
カテゴリやタグが近い記事を続けて読めるように並べています。




