バージョンごとのドキュメント一覧

15.3. パラレルプラン #

<title>Parallel Plans</title>

Because each worker executes the parallel portion of the plan to completion, it is not possible to simply take an ordinary query plan and run it using multiple workers. Each worker would produce a full copy of the output result set, so the query would not run any faster than normal but would produce incorrect results. Instead, the parallel portion of the plan must be what is known internally to the query optimizer as a <firstterm>partial plan</firstterm>; that is, it must be constructed so that each process that executes the plan will generate only a subset of the output rows in such a way that each required output row is guaranteed to be generated by exactly one of the cooperating processes. Generally, this means that the scan on the driving table of the query must be a parallel-aware scan. 各々のワーカーは完了すべきプランのパラレル部分を実行するので、単に通常のクエリプランを適用し、複数のワーカーを使って実行することはできません。 それぞれのワーカーが結果セットの全体のコピーを生成するので、クエリは通常よりも決して速くなりませんし、不正な結果を生成してしまいます。 そうではなくて、プランのパラレル部分は、クエリオプティマイザの内部で部分プランとして知られているものでなくてはなりません。 すなわち、プランを実行する各プロセスが、要求される個々の出力行が、協調動作するプロセスの正確に1個だけによって生成されることが保証されているような方法で、出力行の一部だけを生成します。 一般に、これはクエリの処理対象のテーブルに対するスキャンは、パラレル対応のスキャンでなければならないことを意味します。

15.3.1. パラレルスキャン #

<title>Parallel Scans</title>

The following types of parallel-aware table scans are currently supported. 今のところ、次に示すパラレル対応のテーブルスキャンがサポートされています。

  • In a <emphasis>parallel sequential scan</emphasis>, the table's blocks will be divided into ranges and shared among the cooperating processes. Each worker process will complete the scanning of its given range of blocks before requesting an additional range of blocks. パラレルシーケンシャルスキャンでは、テーブルのブロックは範囲に分割され、協調するプロセス間で共有されます。 各ワーカープロセスは、ブロックの追加範囲を要求する前に、与えられたブロックの範囲のスキャンを完了します。

  • In a <emphasis>parallel bitmap heap scan</emphasis>, one process is chosen as the leader. That process performs a scan of one or more indexes and builds a bitmap indicating which table blocks need to be visited. These blocks are then divided among the cooperating processes as in a parallel sequential scan. In other words, the heap scan is performed in parallel, but the underlying index scan is not. パラレルビットマップヒープスキャンでは、一つのプロセスがリーダーに選ばれます。 そのプロセスは、一つ以上のインデックスをスキャンし、アクセスする必要のあるブロックを示すビットマップを作成します。 次にこれらのブロックは、パラレルシーケンシャルスキャン同様、協調するプロセスに割り当てられます。 つまり、ヒープスキャンは並列であるものの、対応するインデックスのスキャンは並列ではありません。

  • In a <emphasis>parallel index scan</emphasis> or <emphasis>parallel index-only scan</emphasis>, the cooperating processes take turns reading data from the index. Currently, parallel index scans are supported only for btree indexes. Each process will claim a single index block and will scan and return all tuples referenced by that block; other processes can at the same time be returning tuples from a different index block. The results of a parallel btree scan are returned in sorted order within each worker process. パラレルインデックススキャンあるいはパラレルインデックスオンリースキャンでは、協調するプロセスは、交代でインデックスからデータを読み込みます。 今のところ、パラレルインデックススキャンは、btreeインデックスのみでサポートされています。 個々のプロセスは単一のインデックスブロックを要求し、スキャンしてそのブロックから参照されているすべてのタプルを返却します。 他のプロセスは同時に他のインデックスからタプルを返却することができます。 並列btreeスキャンの結果は、ワーカー内におけるソート順の結果で返却されます。

Other scan types, such as scans of non-btree indexes, may support parallel scans in the future. btree以外のインデックススキャンのような他のスキャンタイプは、将来パラレルスキャンをサポートするかもしれません。

15.3.2. パラレルジョイン #

<title>Parallel Joins</title>

Just as in a non-parallel plan, the driving table may be joined to one or more other tables using a nested loop, hash join, or merge join. The inner side of the join may be any kind of non-parallel plan that is otherwise supported by the planner provided that it is safe to run within a parallel worker. Depending on the join type, the inner side may also be a parallel plan. 非パラレルプランと同様、処理対象のテーブルは、1個以上の他のテーブルとネステッドループ、ハッシュ結合、マージ結合で結合することができます。 結合の内側は、パラレルワーカー中で実行しても安全だという条件下で、プランナがサポートするどのような非パラレルプランであっても構いません。 結合タイプによっては内側がパラレルプランであってもよいです。

  • In a <emphasis>nested loop join</emphasis>, the inner side is always non-parallel. Although it is executed in full, this is efficient if the inner side is an index scan, because the outer tuples and thus the loops that look up values in the index are divided over the cooperating processes. ネステッドループ結合では、内側は常に非パラレルです。 外側タプルとこのようなインデックスで値を探すループは共同するプロセス間で分割されるので、全体で実行されても内側がインデックススキャンであるなら、これは効率的です。

  • In a <emphasis>merge join</emphasis>, the inner side is always a non-parallel plan and therefore executed in full. This may be inefficient, especially if a sort must be performed, because the work and resulting data are duplicated in every cooperating process. マージ結合では、内側は常に非パラレルプランで、それゆえに全体で実行されます。 特にソート実行を要する場合、全ての共同プロセスで処理と結果データが重複するので、これは非効率的と考えられます。

  • In a <emphasis>hash join</emphasis> (without the "parallel" prefix), the inner side is executed in full by every cooperating process to build identical copies of the hash table. This may be inefficient if the hash table is large or the plan is expensive. In a <emphasis>parallel hash join</emphasis>, the inner side is a <emphasis>parallel hash</emphasis> that divides the work of building a shared hash table over the cooperating processes. (parallelが付かない)ハッシュ結合では、内側は全ての共同プロセスがハッシュテーブルの同じコピーを作ることで、全体で実行されます。 ハッシュテーブルが大きかったり、そのプランが高価である場合、これは非効率的と考えられます。 パラレルハッシュ結合では、内側は共有ハッシュテーブルの構築処理を共同プロセス間で分割するパラレルハッシュです。

15.3.3. パラレル集約 #

<title>Parallel Aggregation</title>

<productname>PostgreSQL</productname> supports parallel aggregation by aggregating in two stages. First, each process participating in the parallel portion of the query performs an aggregation step, producing a partial result for each group of which that process is aware. This is reflected in the plan as a <literal>Partial Aggregate</literal> node. Second, the partial results are transferred to the leader via <literal>Gather</literal> or <literal>Gather Merge</literal>. Finally, the leader re-aggregates the results across all workers in order to produce the final result. This is reflected in the plan as a <literal>Finalize Aggregate</literal> node. PostgreSQLは、ふたつのステージで集約処理を行うことによってパラレル集約処理をサポートします。 まず、クエリのパラレル部分に参加している個々のプロセスが集約ステップを実行し、それぞれのプロセスが認識しているグループに対する部分的な結果を生成します。 これはPartial Aggregateノードとしてプラン中に反映されています。 次に、GatherまたはGather Mergeノードを通じて部分的な結果がリーダーに転送されます。 最後に、リーダーは、すべてのワーカーにまたがる結果を再集約して、最終的な結果を生成します。 これは、Finalize Aggregateノードとしてプラン中に反映されています。

Because the <literal>Finalize Aggregate</literal> node runs on the leader process, queries that produce a relatively large number of groups in comparison to the number of input rows will appear less favorable to the query planner. For example, in the worst-case scenario the number of groups seen by the <literal>Finalize Aggregate</literal> node could be as many as the number of input rows that were seen by all worker processes in the <literal>Partial Aggregate</literal> stage. For such cases, there is clearly going to be no performance benefit to using parallel aggregation. The query planner takes this into account during the planning process and is unlikely to choose parallel aggregate in this scenario. Finalize Aggregateノードはリーダープロセスで実行されるので、入力行数の割には、比較的多数のグループを生成するクエリは、クエリプランナはあまり好ましくないものとして認識します。 たとえば最悪の場合、Finalize Aggregateノードが認識するグループ数は、Partial Aggregateですべてのワーカープロセスが認識する入力行数と同じだけの数になります。 こうした場合には、明らかにパラレル集約を利用する性能上の利点がないことになります。 クエリプランナはプラン処理中にこれを考慮するので、このシナリオでパラレル集約を採用することはまずありません。

Parallel aggregation is not supported in all situations. Each aggregate must be <link linkend="parallel-safety">safe</link> for parallelism and must have a combine function. If the aggregate has a transition state of type <literal>internal</literal>, it must have serialization and deserialization functions. See <xref linkend="sql-createaggregate"/> for more details. Parallel aggregation is not supported if any aggregate function call contains <literal>DISTINCT</literal> or <literal>ORDER BY</literal> clause and is also not supported for ordered set aggregates or when the query involves <literal>GROUPING SETS</literal>. It can only be used when all joins involved in the query are also part of the parallel portion of the plan. どんな状況でもパラレル集約がサポートされているわけではありません。 個々の集約は並列処理安全で、結合関数(combine function)を持っていなければなりません。 その集約がinternal型の遷移状態を持っているならば、シリアライズ関数とデシリアライズ関数を持っていなければなりません。 更なる詳細はCREATE AGGREGATEをご覧ください。 パラレル集約は、集約関数呼び出しがDISTINCTあるいはORDER BY句を含む場合、また 順序集合集約、あるいはクエリがGROUPING SETSを実行する場合にはサポートされません。 パラレル集約は、クエリの中で実行されるすべての結合が、プラン中の並列実行部分の一部であるときにのみ利用できます。

15.3.4. パラレルアペンド #

<title>Parallel Append</title>

Whenever <productname>PostgreSQL</productname> needs to combine rows from multiple sources into a single result set, it uses an <literal>Append</literal> or <literal>MergeAppend</literal> plan node. This commonly happens when implementing <literal>UNION ALL</literal> or when scanning a partitioned table. Such nodes can be used in parallel plans just as they can in any other plan. However, in a parallel plan, the planner may instead use a <literal>Parallel Append</literal> node. PostgreSQLが複数のソースから一つの結果セットへの行の連結を必要とするときはいつでも、AppendまたはMergeAppendプランノードが使われます。 これは一般にUNION ALLを実施するときや、パーティションテーブルをスキャンするときに発生します。 他のプランと同様にこのようなノードをパラレルプランで使うことができます。 しかしながら、パラレルプランではプランナは代わりにParallel Appendノードを使ってもよいです。

When an <literal>Append</literal> node is used in a parallel plan, each process will execute the child plans in the order in which they appear, so that all participating processes cooperate to execute the first child plan until it is complete and then move to the second plan at around the same time. When a <literal>Parallel Append</literal> is used instead, the executor will instead spread out the participating processes as evenly as possible across its child plans, so that multiple child plans are executed simultaneously. This avoids contention, and also avoids paying the startup cost of a child plan in those processes that never execute it. Appendノードがパラレルプランで使われるとき、各プロセスは子プランをそれらの出現順に実行します。そのため、全ての参加しているプロセスは共同して最初の子プランを完了するまで実行して、その後、一斉に次プランに移ります。 代わりにParallel Appendが使われるときには、エグゼキュータは逆に参加しているプロセスを各子プランにできるだけ均等に分散させます。そのため、複数の子プランは同時並行に実行されます。 これは競合を回避し、また、プランを実行することのないプロセスで子プランの開始コストが生じることも回避します。

Also, unlike a regular <literal>Append</literal> node, which can only have partial children when used within a parallel plan, a <literal>Parallel Append</literal> node can have both partial and non-partial child plans. Non-partial children will be scanned by only a single process, since scanning them more than once would produce duplicate results. Plans that involve appending multiple results sets can therefore achieve coarse-grained parallelism even when efficient partial plans are not available. For example, consider a query against a partitioned table that can only be implemented efficiently by using an index that does not support parallel scans. The planner might choose a <literal>Parallel Append</literal> of regular <literal>Index Scan</literal> plans; each individual index scan would have to be executed to completion by a single process, but different scans could be performed at the same time by different processes. また、パラレルプランの中で使われるときだけ部分的な子プランを持てる、通常のAppendノードと違い、Parallel Appendノードは部分的、非部分的のどちらの子プランも持つことができます。 複数回のスキャンは重複した結果をもたらすため、非部分的な子プランは単一プロセスのみからスキャンされます。 複数の結果セットの連結に関わるプランは、効率的なパラレルプランが不可能なときでも、それゆえ粗い並列性を実現できます。 例えば、パラレルスキャンをサポートしないインデックスを使うことでのみ効率的に実行できるパーティションテーブルに対する問い合わせを考えてください。 プランナは通常のIndex ScanプランのParallel Appendを選ぶことができます。 個々のインデックススキャンは単一プロセスで最後まで実行しなければなりませんが、別のスキャンは同時に別プロセスで実行することができます。

<xref linkend="guc-enable-parallel-append" /> can be used to disable this feature. 本機能を無効にするためにenable_parallel_appendを使用できます。

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

<title>Parallel Plan Tips</title>

If a query that is expected to do so does not produce a parallel plan, you can try reducing <xref linkend="guc-parallel-setup-cost"/> or <xref linkend="guc-parallel-tuple-cost"/>. Of course, this plan may turn out to be slower than the serial plan that the planner preferred, but this will not always be the case. If you don't get a parallel plan even with very small values of these settings (e.g., after setting them both to zero), there may be some reason why the query planner is unable to generate a parallel plan for your query. See <xref linkend="when-can-parallel-query-be-used"/> and <xref linkend="parallel-safety"/> for information on why this may be the case. パラレルプランを生成すると期待していたクエリがそうならない場合には、parallel_setup_costまたはparallel_tuple_costを減らしてみてください。 もちろん、このプランは結局のところ、プランナが選択した順次実行プランよりも遅いということもあり得ますが、いつもそうだとは限りません。 これらの設定値を非常に小さく(つまり両方とも0に)したにも関わらずパラレルプランを得られない場合、あなたのクエリのためにクエリプランナがパラレルプランを生成できない何か理由があるのかもしれません。 そうしたケースに該当しているかどうかを、15.215.4を参照して確認してください。

When executing a parallel plan, you can use <literal>EXPLAIN (ANALYZE, VERBOSE)</literal> to display per-worker statistics for each plan node. This may be useful in determining whether the work is being evenly distributed between all plan nodes and more generally in understanding the performance characteristics of the plan. パラレルプランを実行する際には、EXPLAIN (ANALYZE, VERBOSE)を使って個々のプランノードに対するワーカーごとの状態を表示することができます。 これは、すべてのプランノードに均等に仕事が分散されているかどうかを確認すること、そしてもっと一般的には、プランの性能特性を理解するのに役に立つかもしれません。