

# RDS for PostgreSQL での並列クエリのベストプラクティス
<a name="PostgreSQL.ParallelQueries"></a>

並列クエリ実行は、PostgreSQL の機能であり、単一の SQL クエリをより小さなタスクに分割し、複数のバックグラウンドワーカープロセスによって同時に処理することを可能にします。PostgreSQL は、クエリ全体を単一のバックエンドプロセスで実行する代わりに、スキャン、結合、集約、ソートなどのクエリの一部を複数の CPU コアに分散させることができます。*リーダープロセス*は、この実行を調整し、*並列ワーカー*から結果を収集します。

ただし、ほとんどの本稼働ワークロード、特に高同時実行 OLTP システムでは、自動並列クエリ実行を無効にすることをお勧めします。並列処理は、分析またはレポートワークロードの大規模なデータセットに対するクエリを高速化できますが、負荷の高い本番環境では、多くの場合、メリットを上回る重大なリスクをもたらします。

並列実行では、大きなオーバーヘッドも発生します。各並列ワーカーは完全な PostgreSQL バックエンドプロセスであり、プロセスのフォーク (メモリ構造のコピーとプロセス状態の初期化) と認証 (`max_connections` 制限の接続スロットの消費) が必要です。各ワーカーは、ソートやハッシュ操作のための `work_mem` を含め、独自のメモリも消費します。クエリごとに複数のワーカーがある場合、メモリ使用量は急速に増加します (例: 4 つのワーカー × 64MB `work_mem` = クエリあたり 256MB)。その結果、並列クエリは単一プロセスクエリよりもかなり多くのシステムリソースを消費する可能性があります。正しくチューニングされていない場合は、CPU 飽和 (複数のワーカーが使用可能な処理能力を圧倒する)、コンテキスト切り替えの増加 (オペレーティングシステムが多数のワーカープロセスを頻繁に切り替えるため、オーバーヘッドが増加しスループットが低下する)、または接続の枯渇 (各並列ワーカーが接続スロットを消費するため、4 つのワーカーを含む単一のクエリでは、リーダー 1 つとワーカー 4 つの合計 5 つの接続が使用され、高い同時実行性のもとでは接続プールがすぐに枯渇し、新しいクライアント接続が妨げられ、アプリケーション障害が発生する) につながる可能性があります。これらの問題は、複数のクエリが同時に並列実行を試みる可能性がある同時実行性の高いワークロードでは特に深刻です。

PostgreSQL は、コスト見積もりに基づいて並列処理を使用するかどうかを決定します。場合によっては、プランナーは、実際には理想的でない場合でも、より安価に見える場合、並列プランに自動的に切り替えることがあります。これは、インデックス統計が古くなった場合や、肥大化してシーケンシャルスキャンがインデックス検索よりも魅力的に見える場合に発生する可能性があります。この動作により、自動並列プランによってクエリのパフォーマンスやシステムの安定性にリグレッションを引き起こすことがあります。

RDS for PostgreSQL で並列クエリを最大限に活用するには、ワークロードに基づいて並列クエリをテストおよびチューニングし、システムへの影響をモニタリングし、自動並列プラン選択を無効にして、クエリレベルで制御することが重要です。

## 設定パラメータ
<a name="PostgreSQL.ParallelQueries.ConfigurationParameters"></a>

PostgreSQL は、複数のパラメータを使用して並列クエリの動作と可用性を制御します。これらを理解して調整することは、予測可能なパフォーマンスを達成するために不可欠です。


| パラメータ | 説明 | デフォルト | 
| --- | --- | --- | 
| max\$1parallel\$1workers | 同時に実行できるバックグラウンドワーカープロセスの最大数 | GREATEST(\$1DBInstanceVCPU/2,8) | 
| max\$1parallel\$1workers\$1per\$1gather | クエリプランノードあたりのワーカーの最大数 (例: Gather あたり) | 2 | 
| parallel\$1setup\$1cost | 並列クエリインフラストラクチャを開始するためのプランナーコストの追加 | 1,000 | 
| parallel\$1tuple\$1cost | 並列モードで処理されたタプルあたりのコスト (プランナーの決定に影響する) | 0.1 | 
| force\$1parallel\$1mode | プランナーに並列プランのテストを強制する (off、on、regress) | off | 

### 主な考慮事項
<a name="PostgreSQL.ParallelQueries.ConfigurationParameters.KeyConsiderations"></a>
+ `max_parallel_workers` は、並列ワーカーの合計プールを制御します。設定が低すぎると、一部のクエリが直列実行にフォールバックする可能性があります。
+ `max_parallel_workers_per_gather` は、単一のクエリで使用できるワーカーの数に影響します。値を大きくすると、同時実行数は増加しますが、リソースの使用量も増加します。
+ `parallel_setup_cost` と `parallel_tuple_cost` は、プランナーのコストモデルに影響を与えます。これらの値を下げると、並列プランを選択する可能性が高くなります。
+ `force_parallel_mode` はテストに便利ですが、必要でない限り本番環境では使用しないでください。

**注記**  
`max_parallel_workers` パラメータのデフォルト値は、式 `GREATEST($DBInstanceVCPU/2, 8)` を使用してインスタンスサイズに基づいて動的に計算されます。つまり、DB インスタンスをより多くの vCPU でより大きなコンピューティングサイズにスケールすると、使用可能な並列ワーカーの最大数が自動的に増加します。その結果、以前に連続して実行されたクエリや、並列処理が制限されたクエリでは、スケールアップ操作後に突然、より多くの並列ワーカーが使用され、接続使用量、CPU 使用率、メモリ消費量が予期せず増加する可能性があります。コンピューティングスケーリングイベントの後に並列クエリの動作をモニタリングし、予測可能なリソース使用量を維持するために必要に応じて `max_parallel_workers_per_gather` を調整することが重要です。

## 並列クエリの使用状況を特定する
<a name="PostgreSQL.ParallelQueries.IdentifyUsage"></a>

クエリは、データの分布または統計に基づいて並列プランに切り替わる場合があります。例えば、次のようになります。

```
SELECT count(*) FROM customers WHERE last_login < now() - interval '6 months';
```

このクエリは、最近のデータにインデックスを使用しますが、履歴データに対しては並列シーケンシャルスキャンに切り替える可能性があります。

`auto_explain` モジュールをロードすることでクエリ実行計画を記録できます。詳細については、AWS ナレッジセンターの「[クエリ実行計画のログ記録](https://aws.amazon.com/premiumsupport/knowledge-center/rds-postgresql-tune-query-performance/#)」をご覧ください。



[CloudWatch Database Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Database-Insights-Database-Instance-Dashboard.html) を使用すると、並列クエリに関連する待機イベントをモニタリングできます。並列クエリに関連する待機イベントの詳細については、「[IPC:parallel 待機イベント](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/apg-ipc-parallel.html)」を参照してください。

PostgreSQL バージョン 18 以降では、[https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-DATABASE-VIEW](https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-DATABASE-VIEW) と [https://www.postgresql.org/docs/current/pgstatstatements.html](https://www.postgresql.org/docs/current/pgstatstatements.html) の新しい列を使用して、並列ワーカーのアクティビティをモニタリングできます。
+ `parallel_workers_to_launch`: 起動が予定されている並列ワーカーの数
+ `parallel_workers_launched`: 実際に起動された並列ワーカーの数

これらのメトリクスは、計画された並列処理と実際の並列処理との間の差異を特定するのに役立ち、リソースの制約や設定の問題を示している可能性があります。次のクエリを使用して、並列実行をモニタリングします。

データベースレベルの並列ワーカーメトリクスの場合。

```
SELECT datname, parallel_workers_to_launch, parallel_workers_launched
FROM pg_stat_database
WHERE datname = current_database();
```

クエリレベルの並列ワーカーメトリクスの場合

```
SELECT query, parallel_workers_to_launch, parallel_workers_launched
FROM pg_stat_statements
ORDER BY parallel_workers_launched;
```

## 並列処理を制御する方法
<a name="PostgreSQL.ParallelQueries.ControlParallelism"></a>

クエリの並列処理を制御するにはいくつかの方法があり、それぞれがさまざまなシナリオと要件に合わせて設計されています。

自動並列処理をグローバルに無効にするには、[パラメータグループを変更して](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.Modifying.html)、次のように設定します。

```
max_parallel_workers_per_gather = 0;
```

永続的なユーザー固有の設定の場合、ALTER ROLE コマンドを使用すると、特定のユーザーの今後のすべてのセッションに適用されるパラメータを設定できます。

例えば、次のようになります。

`ALTER ROLE username SET max_parallel_workers_per_gather = 4;` は、このユーザーがデータベースに接続するたびに、セッションが必要に応じてこの並列ワーカー設定を使用するようにします。

セッションレベルの制御は、現在のデータベースセッションの期間中にパラメータを変更する SET コマンドを使用して実現できます。これは、他のユーザーや今後のセッションに影響を与えることなく、設定を一時的に調整する必要がある場合に特に便利です。設定すると、これらのパラメータは明示的にリセットされるまで、またはセッションが終了するまで有効です。コマンドは簡単です。

```
SET max_parallel_workers_per_gather = 4;
-- Run your queries
RESET max_parallel_workers_per_gather;
```

さらに詳細な制御を行うには、SET LOCAL を使用すると、単一のトランザクションのパラメータを変更できます。これは、トランザクション内の特定のクエリセットの設定を調整する必要がある場合に最適です。その後、設定は自動的に以前の値に戻ります。このアプローチは、同じセッション内の他のオペレーションへの意図しない影響を防ぐのに役立ちます。

## 並列クエリ動作の診断
<a name="PostgreSQL.ParallelQueries.Diagnosing"></a>

`EXPLAIN (ANALYZE, VERBOSE)` を使用して、クエリが並列実行を使用したかどうかを確認します。
+ `Gather`、`Gather Merge`、`Parallel Seq Scan` などのノードを探します。
+ 並列処理ありの場合と並列処理なしの場合の計画を比較します。

比較のために並列処理を一時的に無効にするには。

```
SET max_parallel_workers_per_gather = 0;
EXPLAIN ANALYZE <your_query>;
RESET max_parallel_workers_per_gather;
```