他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

15.3. パラレルプラン

各々のワーカーは完了すべきプランのパラレル部分を実行するので、単に通常のクエリプランを適用し、複数のワーカーを使って実行することはできません。 それぞれのワーカーが結果セットの全体のコピーを生成するので、クエリは通常よりも決して速くなりませんし、不正な結果を生成してしまいます。 そうではなくて、プランのパラレル部分は、クエリオプティマイザの内部で部分プランとして知られているものでなくてはなりません。 すなわち、プランを実行する各プロセスが、要求される個々の出力行が、協調動作するプロセスの正確に1個だけによって生成されることが保証されているような方法で、出力行の一部だけを生成します。 一般に、これはクエリの処理対象のテーブルに対するスキャンは、パラレル対応のスキャンでなければならないことを意味します。

15.3.1. パラレルスキャン

今のところ、次に示すパラレル対応のテーブルスキャンがサポートされています。

  • パラレルシーケンシャルスキャンでは、テーブルのブロックは、協調するプロセスに分割して割り当てられます。 ブロックは一度に1個ずつ処理され、テーブルへのアクセスは逐次のままです。

  • パラレルビットマップヒープスキャンでは、一つのプロセスがリーダーに選ばれます。 そのプロセスは、一つ以上のインデックスをスキャンし、アクセスする必要のあるブロックを示すビットマップを作成します。 次にこれらのブロックは、パラレルシーケンシャルスキャン同様、協調するプロセスに割り当てられます。 つまり、ヒープスキャンは並列であるものの、対応するインデックスのスキャンは並列ではありません。

  • パラレルインデックススキャンあるいはパラレルインデックスオンリースキャンでは、協調するプロセスは、交代でインデックスからデータを読み込みます。 今のところ、パラレルインデックススキャンは、btreeインデックスのみでサポートされています。 個々のプロセスは単一のインデックスブロックを要求し、スキャンしてそのブロックから参照されているすべてのタプルを返却します。 他のプロセスは同時に他のインデックスからタプルを返却することができます。 並列btreeスキャンの結果は、ワーカー内におけるソート順の結果で返却されます。

btree以外のインデックススキャンのような他のスキャンタイプは、将来パラレルスキャンをサポートするかもしれません。

15.3.2. パラレルジョイン

非パラレルプランと同様、処理対象のテーブルは、1個以上の他のテーブルとネステッドループ、ハッシュ結合、マージ結合で結合することができます。 結合の内側は、パラレルワーカー中で実行しても安全だという条件下で、プランナがサポートするどのような非パラレルプランであっても構いません。 たとえば、ネステッドループ結合が選択されると、内側のプランは結合の外側から取得された値を参照するインデックススキャンかもしれません。

個々のワーカーは、内側の結合をフル結合で実行します。 典型的にはこれはネステッドループでは問題ではありません。 しかし、ハッシュあるいはマージ結合が関わる場合には非効率かもしれません。 たとえば、ハッシュ結合では、同一のハッシュテーブルが個々のワーカープロセス内で作成されるので、小さなテーブルの結合では良くても、内側のテーブルが大きい場合には非効率的であることを、この制約は意味します。 マージ結合では、個々のワーカーが別々に内側のリレーションのソートを実行するので遅いかもしれないことを、これは意味します。 もちろん、このタイプのパラレルプランが非効率的な場合には、クエリプランナは通常別のプランを代わりに選択します。(パラレル処理を使わないプランである可能性があります。)

15.3.3. パラレル集約

PostgreSQLは、ふたつのステージで集約処理を行うことによってパラレル集約処理をサポートします。 まず、クエリのパラレル部分に参加している個々のプロセスが集約ステップを実行し、それぞれのプロセスが認識しているグループに対する部分的な結果を生成します。 これはPartial Aggregateノードとしてプラン中に反映されています。 次に、GatherまたはGather Mergeノードを通じて部分的な結果がリーダーに転送されます。 最後に、リーダーは、すべてのワーカーにまたがる結果を再集約して、最終的な結果を生成します。 これは、Finalize Aggregateノードとしてプラン中に反映されています。

Finalize Aggregateノードはリーダープロセスで実行されるので、入力行数の割には、比較的多数のグループを生成するクエリは、クエリプランナはあまり好ましくないものとして認識します。 たとえば最悪の場合、Finalize Aggregateノードが認識するグループ数は、Partial Aggregateですべてのワーカープロセスが認識する入力行数と同じだけの数になります。 こうした場合には、明らかにパラレル集約を利用する性能上の利点がないことになります。 クエリプランナはプラン処理中にこれを考慮するので、このシナリオでパラレル集約を採用することはまずありません。

どんな状況でもパラレル集約がサポートされているわけではありません。 個々の集約は並列処理安全で、合同関数(combine function)を持っていなければなりません。 その集約がinternal型の遷移状態を持っているならば、シリアライズ関数とデシリアライズ関数を持っていなければなりません。 更なる詳細はCREATE AGGREGATEをご覧ください。 パラレル集約は、集約関数呼び出しがDISTINCTあるいはORDER BY句を含む場合、また 順序集合集約、あるいはクエリがGROUPING SETSを実行する場合にはサポートされません。 パラレル集約は、クエリの中で実行されるすべての結合が、プラン中の並列実行部分の一部であるときにのみ利用できます。

15.3.4. パラレルプランに関するヒント

パラレルプランを生成すると期待していたクエリがそうならない場合には、parallel_setup_costまたはparallel_tuple_costを減らしてみてください。 もちろん、このプランは結局のところ、プランナが選択した順次実行プランよりも遅いということもあり得ますが、いつもそうだとは限りません。 これらの設定値を非常に小さく(つまり両方とも0に)したにも関わらずパラレルプランを得られない場合、あなたのクエリのためにクエリプランナがパラレルプランを生成できない何か理由があるのかもしれません。 そうしたケースに該当しているかどうかを、15.215.4を参照して確認してください。

パラレルプランを実行する際には、EXPLAIN (ANALYZE, VERBOSE)を使って個々のプランノードに対するワーカーごとの状態を表示することができます。 これは、すべてのプランノードに均等に仕事が分散されているかどうかを確認すること、そしてもっと一般的には、プランの性能特性を理解するのに役に立つかもしれません。