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

AnalyticDB:実行プラン

最終更新日:Jun 25, 2025

クエリ オプティマイザは、データベースによって管理されているデータ統計を使用して、可能な限り低いコストのクエリ プランを選択します。 コストはディスク I/O で測定され、ディスク ページ フェッチの数として表示されます。 EXPLAIN 文と EXPLAIN ANALYZE 文を使用して、クエリ プランを特定し、最適化できます。

EXPLAIN 文の出力

クエリ プランはノードのツリーです。 クエリ プラン内の各ノードは、テーブル スキャン、結合、集計、ソートなどの単一の操作を表します。 各ノードはすぐ上のノードに行をフィードするため、クエリ プランは下から上に読む必要があります。 クエリ プランの最下位ノードは、通常、シーケンシャル スキャン、インデックスベースのスキャン、またはビットマップ インデックスベースのスキャンなどのテーブル スキャン操作です。 クエリで行の結合、集計、ソートなどの操作が必要な場合は、スキャン ノードの上にこれらの操作を実行するための追加ノードがあります。 最上位のプラン ノードは、AnalyticDB for PostgreSQL モーション ノードです。再配布、ブロードキャスト、または収集します。 これらの操作は、クエリ処理中に計算ノード間で行を移動します。

EXPLAIN 文の出力は、プラン内のノードごとに 1 行あり、ノード タイプと各プラン ノードの実行コストの見積もりを示しています。

  • cost: ディスク ページ フェッチの数に基づいて測定されます。 1.0 は 1 つのシーケンシャル ディスク ページの読み取りに相当します。 最初の見積もりは最初の行を取得するための起動コストであり、2 番目の見積もりはすべての行を取得するための総コストです。

  • rows: プラン ノードによって生成される行の総数を示します。 この数は通常、WHERE 句で指定されたフィルター条件のため、プラン ノードによって処理またはスキャンされた行の数よりも少なくなります。 最上位ノードの見積もりは、クエリが実際に返す、更新する、または削除する行の数を概算します。

  • width: プラン ノードが生成するすべての行の合計バイト数を示します。

次の点に注意してください。

  • ノードのコストには、すべての子ノードのコストが含まれます。 最上位のプラン ノードには、プランの実行コストの推定合計が表示されます。 これは、クエリ オプティマイザが最小化しようとする数値です。

  • コストは、AnalyticDB for PostgreSQL でクエリ プランを実行するのにかかる時間のみを反映します。 特に、コストは結果行をクライアントに送信するのにかかる時間を考慮していません。

EXPLAIN 文の例

次の例では、EXPLAIN 文によって表示されるクエリ プランを読み取る方法について説明します。

EXPLAIN SELECT * FROM names WHERE name = 'Joelle';
                     QUERY PLAN
------------------------------------------------------------
Gather Motion 4:1 (slice1) (cost=0.00..20.88 rows=1 width=13)

   -> Seq Scan on 'names' (cost=0.00..20.88 rows=1 width=13)
         Filter: name::text ~~ 'Joelle'::text

クエリ オプティマイザは、WHERE 句で指定されたフィルター条件に基づいて names テーブルを順次スキャンします。 つまり、クエリ オプティマイザは、スキャンする各行の条件をチェックし、条件を満たす行のみを生成します。 スキャン操作の結果は、収集モーションに渡されます。 収集モーションとは、計算ノードがコーディネーター ノードに行を送信することです。 この例では、4 つの計算ノードがコーディネーター ノードに行を送信しています。これは「4:1」で示されています。 このプランの推定起動コストは 00.00 (コストなし) で、ディスク ページ フェッチの総コストは 20.88 です。 クエリ オプティマイザは、このクエリが 1 行を返すものと見積もっています。

EXPLAIN ANALYZE

EXPLAIN ANALYZE 文は、クエリ プランを表示し、文を実行します。 EXPLAIN ANALYZE 文によって表示されるクエリ プランは、クエリ オプティマイザによって提供される見積もりとともに、実際の実行コストを示します。 さらに、EXPLAIN ANALYZE 文は次の情報を表示します。

  • クエリが実行される合計実行時間 (ミリ秒単位)。

  • クエリ プランの各スライスで使用されるメモリと、クエリ文全体に予約されているメモリ。

  • プラン ノード操作に関与する計算ノードの数。 行を返す計算ノードのみがカウントされます。

  • 操作で最も多くの行を生成した計算ノードによって返された行の最大数。 複数の計算ノードが同じ数の行を生成する場合、EXPLAIN ANALYZE 文は、行の生成に最も時間がかかった計算ノードによって生成された行の数を表示します。

  • 操作で最も多くの行を生成する計算ノードの ID。

  • 操作に必要なメモリ量 (work_mem)。 使用可能なメモリが操作を実行するのに不十分な場合、プランはパフォーマンスが最も低い計算ノードのディスクにスピルされたデータ量を示します。 例:

    Work_mem used: 64K bytes avg, 64K bytes max (seg0).
    Work_mem wanted: 90K bytes avg, 90K byes max (seg0) to lessen
    workfile I/O affecting 2 workers.
  • 最も多くの行を生成する計算ノードが最初の行を取得するのに使用した時間 (ミリ秒単位) と、その計算ノードがすべての行を取得するのにかかった時間。

次の例では、同じクエリを使用して、EXPLAIN ANALYZE 文によって表示されるクエリ プランを読み取る方法について説明します。 プランの太字部分は、各プラン ノードの実際のタイミングと返された行、およびクエリ全体のメモリと時間の統計を示しています。

EXPLAIN ANALYZE SELECT * FROM names WHERE name = 'Joelle';
                     QUERY PLAN
------------------------------------------------------------
Gather Motion 2:1 (slice1; segments: 2) (cost=0.00..20.88 rows=1 width=13)
Rows out: 1 rows at destination with 0.305 ms to first row, 0.537 ms to end, start offset by 0.289 ms.
        -> Seq Scan on names (cost=0.00..20.88 rows=1 width=13)
Rows out: Avg 1 rows x 2 workers. Max 1 rows (seg0) with 0.255 ms to first row, 0.486 ms to end, start offset by 0.968 ms.
                 Filter: name = 'Joelle'::text
 Slice statistics:

      (slice0) Executor memory: 135K bytes.

    (slice1) Executor memory: 151K bytes avg x 2 workers, 151K bytes max (seg0).

Statement statistics: Memory used: 128000K bytes Total runtime: 22.548 ms

このクエリを実行するのにかかった合計時間は 22.548 ミリ秒です。 シーケンシャル スキャン操作には、行を返す計算ノード (seg0) が 1 つだけあり、この計算ノードは 1 行だけを返します。 最初の行を取得するのに 0.255 ミリ秒かかり、すべての行をスキャンするのに 0.486 ミリ秒かかります。 収集モーション (計算ノードがコーディネーター ノードにデータを送信する) は 1 行を受信します。 この操作の合計時間は 0.537 ミリ秒です。

一般的なクエリ オペレーター

スキャン オペレーターは、テーブル内の行をスキャンして、行のセットを見つけます。 次のようなスキャン オペレーターがあります。

  • Seq Scan: テーブル内のすべての行をスキャンします。

  • Append-only Scan: 追加専用行指向テーブルの行をスキャンします。

  • Append-only Columnar Scan: 追加専用列指向テーブルの行をスキャンします。

  • Index Scan: B ツリー インデックスを走査して、テーブルから行をフェッチします。

  • Bitmap Append-only Row-oriented Scan: インデックスから追加専用テーブルの行のポインターを収集し、ディスク上の場所ごとにポインターをソートします。

  • Dynamic Table Scan: 次の関数のいずれかを使用して、スキャンするパーティションを選択します。 関数スキャン ノードには関数が含まれています。

    • gp_partition_expansion: テーブル内のすべてのパーティションを選択します。

    • gp_partition_selection: 等式に基づいてパーティションを選択します。

    • gp_partition_inversion: 範囲式に基づいてパーティションを選択します。

    関数スキャン ノードは、動的に選択されたパーティションのリストを結果ノードに渡し、結果ノードはリストをシーケンス ノードに渡します。

結合演算子には以下が含まれます。

  • Hash Join: 結合列をハッシュ キーとして使用して小さいテーブルからハッシュ テーブルを作成し、大きいテーブルをスキャンして結合列のハッシュ キーを計算し、ハッシュ テーブルをプローブして同じハッシュ キーを持つ行を見つけます。 ハッシュ結合は通常、AnalyticDB for PostgreSQL で最速の結合です。 クエリ プランの Hash Cond は、結合される列を識別します。

  • Nested Loop Join: 大きいテーブルの行を反復処理し、反復ごとに小さいテーブルの行をスキャンします。 この演算子では、一方のテーブルのすべての行をもう一方のテーブルのすべての行と比較できるように、一方のテーブルをブロードキャストする必要があります。 ネスト ループ結合は、小さなテーブル、またはインデックスを使用して制限されているテーブルでうまく機能します。 ネスト ループ結合を大きなテーブルで使用すると、パフォーマンスに影響があります。 enable_nestloop パラメーターを OFF (デフォルト値) に設定して、クエリ オプティマイザがハッシュ結合を優先するようにします。

  • Merge Join: 2 つのテーブルをソートしてマージします。 この演算子は、事前順序付けされたデータに対して高速です。 クエリ オプティマイザがマージ結合を優先するようにするには、enable_mergejoin パラメーターを ON に設定します。

モーション オペレーターは、計算ノード間で行を移動します。 次のようなモーション オペレーターがあります。

  • Broadcast motion: 各計算ノードは行を他のすべての計算ノードに送信するため、すべての計算ノードにテーブルの完全なコピーがあります。 ほとんどの場合、クエリ オプティマイザは小さなテーブルに対してのみブロードキャスト モーションを選択します。 ブロードキャスト モーションは大きなテーブルには適していません。 データが結合キーに分散されていない場合、必要な行は一方のテーブルから別の計算ノードに動的に再配布されます。

  • Redistribute motion: 各計算ノードはデータを再ハッシュし、ハッシュ キーに基づいて適切な計算ノードに行を送信します。

  • Gather motion: すべての計算ノードからの結果データがアセンブルされ、コーディネーター ノードに送信されます。 これは、ほとんどのクエリ プランの最後の操作です。

クエリ プランで発生するその他の演算子には以下が含まれます。

  • Materialize: 副選択を具体化します。

  • InitPlan: 事前クエリを示します。 この演算子は動的パーティション除去で使用され、クエリ オプティマイザによってスキャンされるパーティションの値がシステムにわからない場合に実行されます。

  • Sort: 集計やマージ結合など、順序付けられた行を必要とする別の操作の準備として行をソートします。

  • Group By: 1 つ以上の列で行をグループ化します。

  • Group/Hash Aggregate: ハッシュ アルゴリズムを使用して行を集計します。

  • Append: パーティション テーブルのパーティションからスキャンされた行が結合されるときにデータ セットを連結します。

  • Filter: WHERE 句で指定されたフィルター条件を使用して行を選択します。

  • Limit: 返される行の数を制限します。

クエリ オプティマイザの決定

EXPLAIN 文の出力を見て、ORCA またはレガシ クエリ オプティマイザを使用してクエリ プランが生成されたかどうかを判断できます。 この情報は、EXPLAIN 文出力の最後に表示されます。 [設定] 行には、OPTIMIZER パラメーターの設定が表示されます。 [オプティマイザ ステータス] 行には、ORCA またはレガシ クエリ オプティマイザがクエリ プランを生成するかどうかが表示されます。

次の EXPLAIN 文の出力は、クエリ プランが GPORCA クエリ オプティマイザによって生成されたことを示しています。

                       QUERY PLAN
------------------------------------------------------------------------------------
 Aggregate  (cost=0.00..296.14 rows=1 width=8)
   ->  Gather Motion 2:1  (slice1; segments: 2)  (cost=0.00..295.10 rows=1 width=8)
         ->  Aggregate  (cost=0.00..294.10 rows=1 width=8)
               ->  Table Scan on part  (cost=0.00..97.69 rows=100040 width=1)
 Settings:  optimizer=on
 Optimizer status: PQO version 1.609
(5 rows)
explain select count(*) from part;

次の EXPLAIN 文の出力は、クエリ プランがレガシ クエリ オプティマイザによって生成されたことを示しています。

                       QUERY PLAN
----------------------------------------------------------------------------------------
 Aggregate  (cost=3519.05..3519.06 rows=1 width=8)
   ->  Gather Motion 2:1  (slice1; segments: 2)  (cost=3518.99..3519.03 rows=1 width=8)
         ->  Aggregate  (cost=3518.99..3519.00 rows=1 width=8)
               ->  Seq Scan on part  (cost=0.00..3018.79 rows=100040 width=1)
 Settings:  optimizer=off
 Optimizer status: legacy query optimizer
(5 rows)