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

PolarDB:ePQ実行プランのクエリと分析

最終更新日:May 30, 2024

PolarDB for PostgreSQLでは、Elastic Parallel query (ePQ) 機能を使用して実行されるクエリの実行計画をクエリおよび分析できます。

背景情報

PostgreSQLは、SQL文のパフォーマンスを分析するために使用できるEXPLAINコマンドを提供します。 コマンド出力は、実行に消費された時間やリソースなどの情報を含む、SQL文のクエリプランです。 コマンドを使用して、SQLパフォーマンスのボトルネックをトラブルシューティングできます。

ただし, EXPLAINコマンドは, 1つのノードで実行されるSQL文のパフォーマンス分析にのみ適用できます。 PolarDB for PostgreSQLのePQ機能は、EXPLAINの機能を拡張し、ePQ機能を使用して実行されるマルチノード並列クエリの実行プランのクエリに使用できるようにします。 コマンドを使用して、各演算子のePQ実行計画の実行時間、データスキャン量、メモリ使用量などの統計を収集することもできます。 このような情報は、統一された方法でユーザに提供される。

前提条件

PolarDB for PostgreSQLクラスターは、次のエンジンを実行します。

  • リビジョンバージョンが1.1.22以降のPostgreSQL 11

  • リビジョンバージョンが14.6.6.0以降のPostgreSQL 14

説明

次のいずれかのステートメントを実行して、PolarDB for PostgreSQLクラスターのリビジョンバージョンを照会できます。

  • PostgreSQL 11

    ショーpolar_version;
  • PostgreSQL 14

    select version();

仕組み

ePQのクエリコーディネーター (QC) は、libpqYプロトコルを使用してワーカーと通信します。

  • QCは、作業者にEXPLAIN ANALYZEコマンドを送信する。

  • 各ワーカーは、ローカルプロセスのリソース使用量や実行期間などの統計を収集します。

  • スライスの実行が完了すると、各ワーカーは統計をQCに送信します。

  • QCは、すべてのワーカーが実行を完了するまで待機し、統計計算を実行し、出力を生成します。

image

機能の説明

実行プランの照会

ePQの実行計画がスライスされる。 各スライスは、ギャングと呼ばれるプロセスのグループによって実行されます。 プロセスは、SQL計算の一部を完了するために、計算ノード上のセグメントによって開始される。 ePQは、異なるスライスを実行するギャング間のデータ転送の実行計画にMotion演算子を導入します。 したがって、Motion演算子はスライスの境界として機能します。

ePQは、次の3つのモーション演算子を導入します。

  • PX Coordinator: ソースデータを同じ宛先に集約します。

  • PXブロードキャスト: ソースデータを各宛先にブロードキャストします。

  • PX Hash: ソースデータをハッシュし、データを再配布先に送信します。

  • 次の例は、単純なクエリの実行計画を示しています。

    CREATE TABLE t (id INT);
    polar_enable_pxをオンに設定します。EXPLAIN (コストOFF) SELECT * からt LIMIT 1;
                       クエリ計画
    -------------------------------------------------
     制限
       -> PXコーディネーター6:1 (slice1; セグメント: 6)
             -> tの部分的なSeqスキャン
     Optimizer: PolarDB PX Optimizer
    (4行) 

    上記の実行計画は、Motion演算子によって2つのスライスに分割されます。 slice0は最終結果を受け取るために使用され、slice1はデータをスキャンするために使用されます。

    ePQは、6つのセグメント (segments: 6) を使用し、それぞれがslice1を実行する処理を開始する。 6つのプロセスのそれぞれは、テーブル内のデータの一部をスキャンし (Partial Seq Scan) 、6つのプロセスのデータは、Motion演算子によって、Limit演算子である同じ宛先 (PX Coordinator 6:1) に集約されます。

  • 実行計画のスライスとモーション演算子の数は、クエリの複雑さとともに増加します。 次の例は、複雑なクエリの実行計画を示しています。

    CREATE TABLE t1 (a INT, b INT, c INT);
    polar_enable_pxをオンに設定します。EXPLAIN (COSTS OFF) SELECT SUM(b) からt1グループBY a LIMIT 1;
                             クエリ計画
    ------------------------------------------------------------
     制限
       -> PXコーディネーター6:1 (slice1; セグメント: 6)
             -> GroupAggregate
                   グループキー: a
                   -> 並べ替え
                         ソートキー: a
                         -> PXハッシュ6:6 (slice2; セグメント: 6)
                               ハッシュキー: a
                               -> t1の部分的なSeqスキャン
     Optimizer: PolarDB PX Optimizer
    (10行) 

    上記の実行計画には3つのスライスがあります。 slice2を実行するために6つのプロセス (セグメント: 6) が開始される。 6つのプロセスのそれぞれは、テーブル内のデータの一部をスキャンする。 次に、Motion演算子 (PX Hash 6:6) は、slice1を実行するために使用される他の6つのプロセス (segments: 6) にデータを再配信します。 6つのプロセスのそれぞれが、ソート (並べ替え) および集計 (GroupAggregate) 操作を完了します。 最後に、別のモーションオペレーション (PXコーディネータ6:1) がデータをslice0に集約する。

実行プランの分析

EXPLAINコマンドにANALYZEオプションを追加して、実際にクエリを実行し、実行中にさまざまな統計を収集できます。 この場合、実行計画は表示されるだけでなく実行されます。 ePQの実行計画では、オペレータはプロセスのグループによって実行される。 ePQのEXPLAIN ANALYZEコマンドは、同じ演算子を実行するすべてのプロセスの統計を収集できます。

以下の演算子レベルの統計が収集されます。

  • 演算子実行時間: 演算子を実行するすべてのプロセスの中で最も長い実行時間。

  • 演算子によってスキャンされた行の合計: 演算子を実行するすべてのプロセスによってスキャンされた行の合計。

  • 演算子実行ループ: 演算子を実行するすべてのプロセスのループの合計。

  • 演算子リソース使用量: 演算子を実行するすべてのプロセスのリソース使用量の合計。

さらに、ePQのEXPLAIN ANALYZEコマンドは、演算子を実行する各プロセスの統計を収集できます。 これにより、実行中にデータスキューが発生したかどうかを判断できます。 以下のプロセスレベルの統計が収集されます。

  • 各プロセスのメモリ使用量

  • 各プロセスの実行时间

  • 各プロセスで処理される行数

  1. テーブルを作成し、テーブルにデータを挿入します。

    CREATE TABLE t2 (a INT, b INT, c VARCHAR(20));
    INSERT INTO t2 SELECT i, i * 2, to_char(i, 'FM00000') FROM generate_series(1, 100000) i; 
  2. 関連するパラメーターを設定し、EXPLAIN ANALYZEコマンドを実行します。

    SET polar_enable_pxをオンにします。polar_px_enable_explain_all_statをオンに設定します。polar_px_explain_memory_verbosityを詳細に設定します。EXPLAIN (コストオフ、分析) SELECT * FROM t2;
                                            クエリ計画
    -------------------------------------------------------------------------------------------
     PXコーディネーター6:1 (slice1; segments: 6) (実時間=0.816 .. 54.225行=100000ループ=1)
       Executor Memory: 9kB worker: 1 Max: 9kB (worker -1)
       -> t2の部分Seqスキャン (実際の時間=0.052 .. 24.732行=94720ループ=1)
             Executorメモリ: 326kBワーカー: 6 Max: 145kB (ワーカー1)
             allstat:
                 ワーカー: 0, first_time:7.396(ms), total_time:25(ms), total_num:94720
                 worker:1, first_time:7.396(ms), total_time:2.819(ms), total_num:5280
                 worker:2, first_time:7.393(ms), total_time:0.074(ms), total_num:0
                 worker:3, first_time:7.400(ms), total_time:0.078(ms), total_num:0
                 worker:4, first_time:7.402(ms), total_time:0.086(ms), total_num:0
                 worker:5, first_time:7.399(ms), total_time:0.098(ms), total_num:0
             ワーカーごとの動的ページ: [512,29]
     計画時間: 9.768 ms
     Optimizer: PolarDB PX Optimizer
       (slice0) 実行メモリ: 38Kバイト。
       (slice1) Executorメモリ: 68Kバイトavg × 6ワーカー、164Kバイトmax (seg1) 。
     実行時間: 65.572 ms
    (17行) 

    前述の実行計画では、

    • 各オペレータのExecutor Memoryセクションには、オペレータを実行するすべてのプロセスのメモリ使用量の合計、プロセス数、およびメモリ使用量が最も多いプロセスのIDが表示されます。

    • allstatセクションには、演算子を実行する各プロセスの準備時間 (first_time) 、実行時間 (total_time) 、および処理済みタプル数 (total_num) が表示されます。