あるクエリの最速の実行戦略がパラレルクエリであるとオプティマイザが決定すると、Gather ノードを含むクエリプランを作成します。 単純な例を示します。
EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%'; QUERY PLAN ------------------------------------------------------------------------------------- Gather (cost=1000.00..217018.43 rows=1 width=97) Workers Planned: 2 -> Parallel Seq Scan on pgbench_accounts (cost=0.00..216018.33 rows=1 width=97) Filter: (filler ~~ '%x%'::text) (4 rows)
どの場合でも、Gather
ノードは正確に一つの子ノードを持ちます。
子プランは、プランの中で並列に実行される部分です。
Gather
ノードがプランツリーの中で最上位にある場合は、クエリ全体が並列に実行されます。
Gather
ノードがプランツリーの他の部分にある場合は、その部分だけが並列に実行されます。
上の例では、クエリはただ一つのテーブルにアクセスするので、Gather
ノード自身以外では、たった一つのプランノードだけが存在します。
そのプランノードはGather
ノードの子ノードなので、並列に実行されます。
EXPLAINを使って、プランナが選択したワーカーの数を見ることができます。
クエリの実行中にGather
ノードに到達すると、ユーザのセッションに対応しているプロセスは、プランナが選択したワーカーと同じ数のバックグラウンドワーカープロセスを要求します。
ある時点で存在できるバックグラウンドワーカーの数は、max_worker_processesによって制限されるので、あるパラレルクエリが、プラン時よりも少ない数のワーカープロセスによって実行されたり、まったくワーカープロセスなしに実行されることがあり得ます。
最適なプランは利用可能なワーカーの数に依存することもあるので、これは低い性能をもたらす結果になるかもしれません。
これがしばしば起こるようなら、max_worker_processes
を増やしてより多くのワーカーが同時に実行できるようにするか、 max_parallel_workers_per_gatherを減らして、プランナがより少ない数のワーカーを要求するようにすることを考慮してください。
与えられたパラレルクエリから起動されたすべてのバックグラウンドワーカープロセスは、Gather
ノードの子孫であるプランの一部を実行します。
リーダーはそうしたプランの部分を実行するだけでなく、追加の任務が与えられます。
ワーカーが生成したすべてのタプルを読み込まなければなりません。
プラン中のパラレル部分が少数のタプルを生成する場合は、リーダーは追加のワーカーとほぼ同じように振る舞い、クエリの実行を高速化します。
反対にプラン中のパラレル部分が大量のタプルを生成する場合は、リーダーはワーカーが生成したタプルの読み込みと、Gather
ノードより上位のプランノードが要求する追加の処理ステップに忙殺されるかもしれません。
そのような場合は、リーダーはプランの並列実行部分のごく一部しか処理しません。