すべてのプロダクト
Search
ドキュメントセンター

PolarDB:パラレルプラン

最終更新日:Jun 03, 2024

各ワーカーはプランの並列部分を実行して完了するため、通常のクエリプランを単純に取得し、複数のワーカーを使用して実行することはできません。 各ワーカーは出力結果セットの完全なコピーを生成するため、クエリは通常よりも速くは実行されませんが、誤った結果が生成されます。 すなわち、計画を実行する各プロセスが出力行のサブセットのみを生成し、必要な各出力行が協働するプロセスのうちの1つだけによって生成されることが保証されるように構成されなければならない。 一般に、これは、クエリの駆動テーブル上のスキャンが並列認識スキャンでなければならないことを意味する。

パラレルスキャン

現在、次のタイプの並列対応テーブルスキャンがサポートされています。

  • 並列順次走査では、テーブルのブロックは範囲に分割され、協働するプロセス間で共有される。 各ワーカープロセスは、追加の範囲のブロックを要求する前に、その所与の範囲のブロックの走査を完了する。

  • 並列ビットマップヒープスキャンでは、1つのプロセスがリーダーとして選択されます。 このプロセスは、1つまたは複数のインデックスのスキャンを実行し、どのテーブルブロックを訪問する必要があるかを示すビットマップを構築する。 次いで、これらのブロックは、並列順次走査におけるように、協働するプロセスの間で分割される。 つまり、ヒープスキャンは並列に実行されますが、基礎となるインデックススキャンは実行されません。

  • 並列インデックススキャンまたは並列インデックスのみのスキャンでは、協働するプロセスは、インデックスからデータを順番に読み取る。 現在、並列インデックススキャンはbtreeインデックスでのみサポートされています。 各プロセスは、単一のインデックスブロックを要求し、そのブロックによって参照されるすべてのタプルをスキャンして返す。同時に、他のプロセスは、異なるインデックスブロックからタプルを返すことができる。 並列btreeスキャンの結果は、各ワーカープロセス内でソートされた順序で返されます。

非btreeインデックスのスキャンなどの他のスキャンタイプは、将来的に並列スキャンをサポートする可能性があります。

並列結合

非並列プランと同様に、駆動テーブルは、ネストされたループ、ハッシュ結合、またはマージ結合を使用して、1つまたは複数の他のテーブルに結合され得る。 接合部の内側は、パラレルワーカー内で安全に実行できるという条件で、プランナによってサポートされる任意の種類の非平行プランとすることができる。 結合タイプに応じて、内側は平行プランであってもよい。

  • ネストされたループ結合では、内側は常に非平行です。 これは完全に実行されるが、内側がインデックススキャンである場合には効率的である。なぜなら、外側のタプル、したがってインデックス内の値をルックアップするループは、協働するプロセスにわたって分割されるからである。

  • マージ結合では、内側は常に非並列プランであるため、完全に実行されます。 これは、特にソートを実行しなければならない場合、作業と結果のデータがすべての協調プロセスで複製されるため、非効率的です。

  • (「並列」プレフィックスなしの) ハッシュ結合では、ハッシュテーブルの同一のコピーを構築するために、すべての協調プロセスによって内側が完全に実行されます。 これは、ハッシュテーブルが大きい場合、またはプランが高価である場合、非効率的である。 並列ハッシュ結合では、内側は並列ハッシュであり、共有ハッシュテーブルを構築する作業を、協働するプロセスにわたって分割する。

並列集約

PolarDB PostgreSQLは、2段階で集約することにより、並列集約をサポートします。 第1に、クエリの並列部分に関与する各プロセスは、集約ステップを実行し、そのプロセスが認識している各グループについて部分的な結果を生成する。 これは、Partial Aggregateノードとしてプランに反映されます。 次に、部分的な結果がGatherまたはGather Mergeを介してリーダーに転送されます。 最後に、リーダーは、最終結果を生成するために、すべてのワーカーにわたって結果を再集約する。 これは、Finalize Aggregateノードとしてプランに反映されます。

Finalize Aggregateノードはリーダープロセスで実行されるため、入力行の数と比較して比較的多数のグループを生成するクエリは、クエリプランナーにとってあまり好ましくないように見えます。 たとえば、最悪のシナリオでは、[Finalize Aggregate] ノードで表示されるグループの数は、[Partial Aggregate] ステージのすべてのワーカープロセスで表示された入力行の数と同じになります。 そのような場合、並列集約を使用することによる性能上の利点は明らかにない。 クエリプランナーは、計画プロセス中にこれを考慮に入れ、このシナリオでは並列集計を選択する可能性は低いです。

並列集計は、すべての状況でサポートされていません。 各アグリゲートは並列処理に対して安全である必要があり、結合機能が必要です。 集計にinternal型の遷移状態がある場合は、シリアル化および逆シリアル化関数が必要です。

並列集計は、集計関数呼び出しにDISTINCTまたはORDER BY句が含まれている場合にはサポートされません。また、順序付きセット集計でも、またはクエリにGROUPING SETSが含まれる場合にもサポートされません。 クエリに含まれるすべての結合がプランの並列部分の一部である場合にのみ使用できます。

並列追加

PolarDB PostgreSQLは、複数のソースからの行を1つの結果セットに結合する必要がある場合は常に、AppendまたはMergeAppendプランノードを使用します。 これは、UNION ALLを実装するとき、またはパーティションテーブルをスキャンするときによく発生します。 このようなノードは、他のプランと同様に並列プランで使用できます。 ただし、並列プランでは、プランナーは代わりにparallel Appendノードを使用できます。

Appendノードが並列プランで使用される場合、各プロセスは子プランを表示される順序で実行します。これにより、すべての参加プロセスが協力して最初の子プランを完了するまで実行し、その後ほぼ同時に2番目のプランに移動します。 代わりにParallel Appendを使用すると、エグゼキュータは参加しているプロセスを子プラン全体にできるだけ均等に分散させ、複数の子プランが同時に実行されるようにします。 これにより、競合が回避され、子プランを実行しないプロセスで子プランの開始コストを支払うことも回避されます。

また、通常の [Append] ノードは、並列プラン内で使用する場合に部分的な子のみを持つことができますが、[parallel Append] ノードは、部分的な子プランと非部分的な子プランの両方を持つことができます。 非部分的な子を2回以上スキャンすると重複した結果が生成されるため、非部分的な子は単一のプロセスのみでスキャンされます。 したがって、複数の結果セットを追加するプランは、効率的な部分プランが利用できない場合でも、粗い並列処理を実現できます。 たとえば、並列スキャンをサポートしないインデックスを使用することによってのみ効率的に実装できるパーティションテーブルに対するクエリを検討します。 プランナーは、通常のインデックススキャンプランの並列追加を選択することができます。個々のインデックススキャンは、単一のプロセスによって完了するまで実行する必要がありますが、異なるプロセスによって異なるスキャンを同時に実行できます。

enable_parallel_appendを使用すると、この機能を無効にできます。

並列プランのヒント

そうすることが期待されるクエリで並列計画が生成されない場合は、parallel_setup_costまたはparallel_tup_costを削減してみてください。 もちろん、この計画は計画者が好んだシリアル計画よりも遅いことが判明するかもしれませんが、これは常にそうであるとは限りません。 これらの設定の値が非常に小さい場合でも (たとえば、両方をゼロに設定した後) 、並列プランを取得できない場合は、クエリプランナーがクエリの並列プランを生成できない理由がある可能性があります。

並列プランを実行する場合、EXPLAIN (ANALYZE, VERBOSE) を使用して、各プランノードのワーカーごとの統計を表示できます。 これは、作業がすべてのプランノード間で均等に分散されているかどうかを判断するのに役立ち、より一般的には、プランのパフォーマンス特性を理解するのに役立ちます。