各々のワーカーは完了すべきプランのパラレル部分を実行するので、単に通常のクエリプランを適用し、複数のワーカーを使って実行することはできません。 それぞれのワーカーが結果セットの全体のコピーを生成するので、クエリは通常よりも決して速くなりませんし、不正な結果を生成してしまいます。 そうではなくて、プランのパラレル部分は、クエリオプティマイザの内部で部分プランとして知られているものでなくてはなりません。 すなわち、プランを実行する各プロセスが、要求される個々の出力行が、協調動作するプロセスの正確に1個だけによって生成されることが保証されているような方法で、出力行の一部だけを生成します。
今のところ、パラレルクエリに適合するように修正されたスキャンタイプはシーケンシャルスキャンだけです。
したがって、パラレルプラン中で対象となるテーブルは常にParallel Seq Scan
を使ってスキャンされます。
リレーションのブロックは協調するプロセスの間で分割されます。
リレーションへのアクセスが順次になるように、ブロックは一時に1個だけ渡されます。
個々のプロセスは割り当てられたページのすべてのタプルをアクセスしてから、新しいページを要求します。
処理対象のテーブルは、1個以上の他のテーブルとネステッドループか、ハッシュ結合で結合することができます。 結合の内側は、パラレルワーカー中で実行しても安全だという条件下で、プランナがサポートするどのような非パラレルプランであっても構いません。 たとえば、外側のテーブルの列の値を参照するインデックススキャンでも構いません。 各々のワーカーは内側のプラン全体を実行します。 これはハッシュ結合では、同一のハッシュテーブルがそれぞれのワーカープロセスによって作成されることを意味します。
PostgreSQLは、ふたつのステージで集約処理を行うことによってパラレル集約処理をサポートします。
まず、クエリのパラレル部分に参加している個々のプロセスが集約ステップを実行し、それぞれのプロセスが認識しているグループに対する部分的な結果を生成します。
これはPartial Aggregate
ノードとしてプラン中に反映されています。
次に、Gather
ノードを通じて部分的な結果がリーダーに転送されます。
最後に、リーダーは、すべてのワーカーにまたがる結果を再集約して、最終的な結果を生成します。
これは、Finalize Aggregate
ノードとしてプラン中に反映されています。
Finalize Aggregate
ノードはリーダープロセスで実行されるので、入力行数の割には、比較的多数のグループを生成するクエリは、クエリプランナはあまり好ましくないものとして認識します。
たとえば最悪の場合、Finalize Aggregate
ノードが認識するグループ数は、Partial Aggregate
ですべてのワーカープロセスが認識する入力行数と同じだけの数になります。
こうした場合には、明らかにパラレル集約を利用する性能上の利点がないことになります。
クエリプランナはプラン処理中にこれを考慮するので、このシナリオでパラレル集約を採用することはまずありません。
どんな状況でもパラレル集約がサポートされているわけではありません。
個々の集約は並列処理安全で、合同関数(combine function)を持っていなければなりません。
その集約がinternal
型の遷移状態を持っているならば、シリアライズ関数とデシリアライズ関数を持っていなければなりません。
更なる詳細はCREATE AGGREGATEをご覧ください。
パラレル集約は、集約関数呼び出しがDISTINCT
あるいはORDER BY
句を含む場合、また 順序集合集約、あるいはクエリがGROUPING SETS
を実行する場合にはサポートされません。
パラレル集約は、クエリの中で実行されるすべての結合が、プラン中の並列実行部分の一部であるときにのみ利用できます。
パラレルプランを生成すると期待していたクエリがそうならない場合には、parallel_setup_costまたはparallel_tuple_costを減らしてみてください。 もちろん、このプランは結局のところ、プランナが選択した順次実行プランよりも遅いということもあり得ますが、いつもそうだとは限りません。 これらの設定値を非常に小さく(つまり両方とも0に)したにも関わらずパラレルプランを得られない場合、あなたのクエリのためにクエリプランナがパラレルプランを生成できない何か理由があるのかもしれません。 そうしたケースに該当しているかどうかを、15.2. どのような時にパラレルクエリは使用できるのか?と15.4. パラレル安全を参照して確認してください。
パラレルプランを実行する際には、EXPLAIN (ANALYZE, VERBOSE)
を使って個々のプランノードに対するワーカーごとの状態を表示することができます。
これは、すべてのプランノードに均等に仕事が分散されているかどうかを確認すること、そしてもっと一般的には、プランの性能特性を理解するのに役に立つかもしれません。