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

PolarDB:実行計画管理

最終更新日:Aug 29, 2026

PolarDB-X は、パラメータ化された SQL 文の実行計画をキャッシュすることで、バージョンアップデート後も複雑なクエリのパフォーマンスを安定させます。このメカニズムは、プランキャッシュと SQL プラン管理 (SPM) の 2 つのレイヤーで構成されています。

仕組み

PolarDB-X が SQL ステートメントを受信すると、次の順序でステートメントを処理します。

  1. パラメータ化:ステートメント内のすべての定数値をプレースホルダー文字 (?) に置き換えます。

  2. プランキャッシュの確認:パラメータ化された SQL をキーとして使用し、キャッシュされた実行計画を検索します。キャッシュされたプランが存在しない場合は、オプティマイザーを呼び出して生成します。

  3. 単純なステートメントのルーティング:単純なステートメントは直接実行します。実行計画管理は、複雑なステートメントにのみ適用されます。

  4. 複雑なステートメントに最適なプランの選択:ベースラインに保存されている固定実行計画を使用してステートメントを実行します。ベースラインに複数のプランが存在する場合、プランエニュメレーターはコストが最も低いプランを選択します。

プランキャッシュ

プランキャッシュは、PolarDB-X でデフォルトで有効になっています。パラメータ化の後、PolarDB-X は SQL ステートメント内のすべての定数を ? に置き換え、パラメーターリストを構築します。実行計画では、LogicalView 演算子内の SQL にこれらの ? プレースホルダーが含まれます。

任意のステートメントで EXPLAIN を実行して、プランキャッシュにヒットしたかどうかを確認します。出力の HitCache フィールドが結果を示します。

EXPLAIN SELECT * FROM lineitem JOIN part ON l_partkey=p_partkey WHERE p_name LIKE '%green%';

出力には HitCache:true または HitCache:false のインジケーターが含まれます。

実行計画管理

複雑な SQL ステートメントがプランキャッシュを通過した後、SQL プラン管理 (SPM) がそのステートメントに実行計画管理を適用します。

プランキャッシュと実行計画管理はどちらも、パラメータ化された SQL ステートメントをルックアップキーとして使用します。プランキャッシュはすべての SQL ステートメントを対象としますが、実行計画管理は複雑なクエリにのみ適用されます。

各 SQL ステートメントは、正確に 1 つのベースラインにマッピングされます。ベースラインには、1 つ以上の実行計画が保持されます。SPM は現在のパラメーター値に基づいて各プランのコストを評価し、最もコストの低いプランを選択します。プランキャッシュからの実行計画が SPM に入ると、次のようになります。

  • プランが既知の場合、SPM はそのプランのコストが最も低いかどうかを確認します。

  • プランが未知の場合、SPM はそれを評価して最適化が必要かどうかを判断します。

自動プラン展開中、SPM はプランエニュメレーターによって発見されたより良いプランを自動的にベースラインに追加します。

BASELINE コマンド

PolarDB-X は、実行計画を管理するために BASELINE コマンドファミリーを提供します。

構文:

BASELINE (LOAD|PERSIST|CLEAR|VALIDATE|LIST|DELETE) [Signed Integer, Signed Integer, ...]
BASELINE (ADD|FIX) SQL (HINT Select Statement)

コマンドリファレンス:

コマンド説明
BASELINE ADD SQL <hint> <select>ヒントを使用して生成された実行計画をベースラインに追加します。新しいプランと既存のプランの両方が利用可能なままであり、ランタイム時にプランエニュメレーターが最もコストの低いものを選択します。
BASELINE FIX SQL <hint> <select>実行計画を必須プランとして固定します。PolarDB-X は、パラメーター値に関係なく、常にこのプランを使用します。
BASELINE LISTすべてのベースラインとその実行計画をリスト表示します。
BASELINE LOAD指定されたベースラインをシステムテーブルからメモリにロードします。
BASELINE LOAD_PLAN指定された実行計画をシステムテーブルからメモリにロードします。
BASELINE PERSIST指定されたベースラインをディスクにフラッシュします。
BASELINE PERSIST_PLAN指定された実行計画をディスクにフラッシュします。
BASELINE CLEAR指定されたベースラインをメモリから削除します。
BASELINE CLEAR_PLAN指定された実行計画をメモリから削除します。
BASELINE DELETE指定されたベースラインをディスクから削除します。
BASELINE DELETE_PLAN指定された実行計画をディスクから削除します。

`BASELINE LIST` の出力列:

列説明
BASELINE_IDベースラインの一意の識別子。パラメータ化された SQL から派生します。
PARAMETERIZED_SQLすべての定数が ? に置き換えられた後の SQL ステートメント。
PLAN_IDこのベースライン内での実行計画の一意の識別子。
EXTERNALIZED_PLANシリアル化された論理実行計画ツリー。
FIXEDBASELINE FIX によって固定され、コストに関係なく常に選択される場合は 1。プランがコストベースの選択に参加する場合は 0。
ACCEPTED1 は、このプランが Plan Enumerator によって承認され、選択対象であることを示します。 0 は、プランが検証保留中であることを示します。
ベースラインには、ACCEPTED=1 のプランを複数含めることができます。 FIXED=1 のプランがない場合、Plan Enumerator は実行時に最もコストの低いプランを選択します。 FIXED=1 のプランがある場合、PolarDB-X はコストを無視して常にそのプランを使用します。

実行計画の最適化

データ変更や PolarDB-X オプティマイザーのアップグレード後、クエリに対してより良い実行計画が存在する可能性があります。BASELINE ADD と BASELINE FIX を使用して、より良いプランを導入し、固定します。

次の例では、ハッシュ結合クエリをバッチキーアクセス結合 (BKA 結合) に切り替えて、そのプランを固定する方法を示します。

ステップ 1:現在の実行計画の確認

EXPLAIN を実行して現在のプランを確認し、プランキャッシュにヒットしたことを検証します。

EXPLAIN SELECT * FROM lineitem JOIN part ON l_partkey=p_partkey WHERE p_name LIKE '%green%';

出力:

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| LOGICAL PLAN                                                                                                                                                                                                                                                                                                                                                   |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Gather(parallel=true)                                                                                                                                                                                                                                                                                                                                          |
|   ParallelHashJoin(condition="l_partkey = p_partkey", type="inner")                                                                                                                                                                                                                                                                                            |
|     LogicalView(tables="[00-03].lineitem", shardCount=4, sql="SELECT `l_orderkey`, `l_partkey`, `l_suppkey`, `l_linenumber`, `l_quantity`, `l_extendedprice`, `l_discount`, `l_tax`, `l_returnflag`, `l_linestatus`, `l_shipdate`, `l_commitdate`, `l_receiptdate`, `l_shipinstruct`, `l_shipmode`, `l_comment` FROM `lineitem` AS `lineitem`", parallel=true) |
|     LogicalView(tables="[00-03].part", shardCount=4, sql="SELECT `p_partkey`, `p_name`, `p_mfgr`, `p_brand`, `p_type`, `p_size`, `p_container`, `p_retailprice`, `p_comment` FROM `part` AS `part` WHERE (`p_name` LIKE ?)", parallel=true)                                                                                                                    |
| HitCache:true                                                                                                                                                                                                                                                                                                                                                  |
|                                                                                                                                                                                                                                                                                                                                                                |
|                                                                                                                                                                                                                                                                                                                                                                |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
7 rows in set (0.06 sec)

BASELINE LIST を実行してベースラインを確認します。これには 1 つのプラン (ParallelHashJoin) が含まれており、FIXED=0 および ACCEPTED=1 となっています。

BASELINE LIST;

出力:

+-------------+--------------------------------------------------------------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+----------+
| BASELINE_ID | PARAMETERIZED_SQL                                                              | PLAN_ID    | EXTERNALIZED_PLAN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | FIXED | ACCEPTED |
+-------------+--------------------------------------------------------------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+----------+
|  -399023558 | SELECT *
FROM lineitem
    JOIN part ON l_partkey = p_partkey
WHERE p_name LIKE ? | -935671684 |
Gather(parallel=true)
  ParallelHashJoin(condition="l_partkey = p_partkey", type="inner")
    LogicalView(tables="[00-03].lineitem", shardCount=4, sql="SELECT `l_orderkey`, `l_partkey`, `l_suppkey`, `l_linenumber`, `l_quantity`, `l_extendedprice`, `l_discount`, `l_tax`, `l_returnflag`, `l_linestatus`, `l_shipdate`, `l_commitdate`, `l_receiptdate`, `l_shipinstruct`, `l_shipmode`, `l_comment` FROM `lineitem` AS `lineitem`", parallel=true)
    LogicalView(tables="[00-03].part", shardCount=4, sql="SELECT `p_partkey`, `p_name`, `p_mfgr`, `p_brand`, `p_type`, `p_size`, `p_container`, `p_retailprice`, `p_comment` FROM `part` AS `part` WHERE (`p_name` LIKE ?)", parallel=true)
 |     0 |        1 |
+-------------+--------------------------------------------------------------------------------+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+----------+
1 row in set (0.02 sec)

ステップ 2:ヒントを使用した代替プランの検証

/*+TDDL:BKA_JOIN(lineitem, part)*/ ヒントを使用して、ベースラインを変更せずに BKA 結合プランを生成します。

EXPLAIN /*+TDDL:bka_join(lineitem, part)*/ SELECT * FROM lineitem JOIN part ON l_partkey=p_partkey WHERE p_name LIKE '%green%';

出力:

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 論理プラン                                                                                                                                                                                                                                                                                                                                                     |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Gather(parallel=true)                                                                                                                                                                                                                                                                                                                                          |
|   ParallelBKAJoin(condition="l_partkey = p_partkey", type="inner")                                                                                                                                                                                                                                                                                             |
|     LogicalView(tables="[00-03].lineitem", shardCount=4, sql="SELECT `l_orderkey`, `l_partkey`, `l_suppkey`, `l_linenumber`, `l_quantity`, `l_extendedprice`, `l_discount`, `l_tax`, `l_returnflag`, `l_linestatus`, `l_shipdate`, `l_commitdate`, `l_receiptdate`, `l_shipinstruct`, `l_shipmode`, `l_comment` FROM `lineitem` AS `lineitem`", parallel=true) |
|     Gather(concurrent=true)                                                                                                                                                                                                                                                                                                                                    |
|       LogicalView(tables="[00-03].part", shardCount=4, sql="SELECT `p_partkey`, `p_name`, `p_mfgr`, `p_brand`, `p_type`, `p_size`, `p_container`, `p_retailprice`, `p_comment` FROM `part` AS `part` WHERE (`p_name` LIKE ?)")                                                                                                                                 |
| HitCache:true                                                                                                                                                                                                                                                                                                                                                  |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
8 行 (0.01 秒)

HitCache:false は、ヒントで駆動されるプランがまだベースラインにないことを示します。ベースラインは変更されません。

ステップ 3:BKA 結合プランをベースラインに追加

BASELINE ADD を実行して、既存のハッシュ結合プランと並行して BKA 結合プランを追加します。プランエニュメレーターは、ランタイム時にコストに基づいて両者から選択します。

BASELINE ADD SQL /*+TDDL:bka_join(lineitem, part)*/ SELECT * FROM lineitem JOIN part ON l_partkey=p_partkey WHERE p_name LIKE '%green%';

出力:

+-------------+--------+
| BASELINE_ID | STATUS |
+-------------+--------+
|  -399023558 | OK     |
+-------------+--------+
1 row in set (0.09 sec)

BASELINE LIST は、同じベースライン ID に対して、BKA join プラン (PLAN_ID: -1024543942) と元のハッシュ結合プラン (PLAN_ID: -935671684) の 2 つのプランを表示するようになりました。どちらも FIXED=0 および ACCEPTED=1 となっています。

BASELINE LIST;

出力:

+-------------+--------------------------------------------------------------------------------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+----------+
| BASELINE_ID | PARAMETERIZED_SQL                                                              | PLAN_ID     | EXTERNALIZED_PLAN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | FIXED | ACCEPTED |
+-------------+--------------------------------------------------------------------------------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+----------+
|  -399023558 | SELECT *
FROM lineitem
    JOIN part ON l_partkey = p_partkey
WHERE p_name LIKE ? | -1024543942 |
Gather(parallel=true)
  ParallelBKAJoin(condition="l_partkey = p_partkey", type="inner")
    LogicalView(tables="[00-03].lineitem", shardCount=4, sql="SELECT `l_orderkey`, `l_partkey`, `l_suppkey`, `l_linenumber`, `l_quantity`, `l_extendedprice`, `l_discount`, `l_tax`, `l_returnflag`, `l_linestatus`, `l_shipdate`, `l_commitdate`, `l_receiptdate`, `l_shipinstruct`, `l_shipmode`, `l_comment` FROM `lineitem` AS `lineitem`", parallel=true)
    Gather(concurrent=true)
      LogicalView(tables="[00-03].part", shardCount=4, sql="SELECT `p_partkey`, `p_name`, `p_mfgr`, `p_brand`, `p_type`, `p_size`, `p_container`, `p_retailprice`, `p_comment` FROM `part` AS `part` WHERE (`p_name` LIKE ?)")
 |     0 |        1 |
|  -399023558 | SELECT *
FROM lineitem
    JOIN part ON l_partkey = p_partkey
WHERE p_name LIKE ? |  -935671684 |
Gather(parallel=true)
  ParallelHashJoin(condition="l_partkey = p_partkey", type="inner")
    LogicalView(tables="[00-03].lineitem", shardCount=4, sql="SELECT `l_orderkey`, `l_partkey`, `l_suppkey`, `l_linenumber`, `l_quantity`, `l_extendedprice`, `l_discount`, `l_tax`, `l_returnflag`, `l_linestatus`, `l_shipdate`, `l_commitdate`, `l_receiptdate`, `l_shipinstruct`, `l_shipmode`, `l_comment` FROM `lineitem` AS `lineitem`", parallel=true)
    LogicalView(tables="[00-03].part", shardCount=4, sql="SELECT `p_partkey`, `p_name`, `p_mfgr`, `p_brand`, `p_type`, `p_size`, `p_container`, `p_retailprice`, `p_comment` FROM `part` AS `part` WHERE (`p_name` LIKE ?)", parallel=true)
                   |     0 |        1 |
+-------------+--------------------------------------------------------------------------------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+----------+
2 行がセット内にあります (0.03 秒)

p_name LIKE ? の値が変化すると、PolarDB-X は異なる実行計画を動的に選択します。

ステップ 4: BKA 結合プランの修正

パラメーター値に関係なく BKA 結合計画を常に使用するには、BASELINE FIX を実行します。

BASELINE FIX SQL /*+TDDL:bka_join(lineitem, part)*/ SELECT * FROM lineitem JOIN part ON l_partkey=p_partkey WHERE p_name LIKE '%green%';

出力:

+-------------+--------+
| BASELINE_ID | STATUS |
+-------------+--------+
|  -399023558 | OK     |
+-------------+--------+
1 row in set (0.07 sec)

固定すると、BASELINE LIST には FIXED=1 の BKA 結合計画と FIXED=0 のハッシュ結合計画が表示されます。

mysql> baseline list\G
*************************** 1. row ***************************
      BASELINE_ID: -399023558
PARAMETERIZED_SQL: SELECT *
FROM lineitem
    JOIN part ON l_partkey = p_partkey
WHERE p_name LIKE ?
          PLAN_ID: -1024543942
EXTERNALIZED_PLAN:
Gather(parallel=true)
  ParallelBKAJoin(condition="l_partkey = p_partkey", type="inner")
    LogicalView(tables="[00-03].lineitem", shardCount=4, sql="SELECT `l_orderkey`, `l_partkey`, `l_suppkey`, `l_linenumber`, `l_quantity`, `l_extendedprice`, `l_discount`, `l_tax`, `l_returnflag`, `l_linestatus`, `l_shipdate`, `l_commitdate`, `l_receiptdate`, `l_shipinstruct`, `l_shipmode`, `l_comment` FROM `lineitem` AS `lineitem`", parallel=true)
    Gather(concurrent=true)
      LogicalView(tables="[00-03].part", shardCount=4, sql="SELECT `p_partkey`, `p_name`, `p_mfgr`, `p_brand`, `p_type`, `p_size`, `p_container`, `p_retailprice`, `p_comment` FROM `part` AS `part` WHERE (`p_name` LIKE ?)")
            FIXED: 1
         ACCEPTED: 1
*************************** 2. row ***************************
      BASELINE_ID: -399023558
PARAMETERIZED_SQL: SELECT *
FROM lineitem
    JOIN part ON l_partkey = p_partkey
WHERE p_name LIKE ?
          PLAN_ID: -935671684
EXTERNALIZED_PLAN:
Gather(parallel=true)
  ParallelHashJoin(condition="l_partkey = p_partkey", type="inner")
    LogicalView(tables="[00-03].lineitem", shardCount=4, sql="SELECT `l_orderkey`, `l_partkey`, `l_suppkey`, `l_linenumber`, `l_quantity`, `l_extendedprice`, `l_discount`, `l_tax`, `l_returnflag`, `l_linestatus`, `l_shipdate`, `l_commitdate`, `l_receiptdate`, `l_shipinstruct`, `l_shipmode`, `l_comment` FROM `lineitem` AS `lineitem`", parallel=true)
    LogicalView(tables="[00-03].part", shardCount=4, sql="SELECT `p_partkey`, `p_name`, `p_mfgr`, `p_brand`, `p_type`, `p_size`, `p_container`, `p_retailprice`, `p_comment` FROM `part` AS `part` WHERE (`p_name` LIKE ?)", parallel=true)
            FIXED: 0
         ACCEPTED: 1
2 rows in set (0.01 sec)

ステップ 5: 固定プランを確認する

ヒントワードを付けずに EXPLAIN を再度実行してください。

EXPLAIN SELECT * FROM lineitem JOIN part ON l_partkey=p_partkey WHERE p_name LIKE '%green%';

出力:

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 論理プラン                                                                                                                                                                                                                                                                                                                                                   |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Gather(parallel=true)                                                                                                                                                                                                                                                                                                                                          |
|   ParallelBKAJoin(condition="l_partkey = p_partkey", type="inner")                                                                                                                                                                                                                                                                                             |
|     LogicalView(tables="[00-03].lineitem", shardCount=4, sql="SELECT `l_orderkey`, `l_partkey`, `l_suppkey`, `l_linenumber`, `l_quantity`, `l_extendedprice`, `l_discount`, `l_tax`, `l_returnflag`, `l_linestatus`, `l_shipdate`, `l_commitdate`, `l_receiptdate`, `l_shipinstruct`, `l_shipmode`, `l_comment` FROM `lineitem` AS `lineitem`", parallel=true) |
|     Gather(concurrent=true)                                                                                                                                                                                                                                                                                                                                    |
|       LogicalView(tables="[00-03].part", shardCount=4, sql="SELECT `p_partkey`, `p_name`, `p_mfgr`, `p_brand`, `p_type`, `p_size`, `p_container`, `p_retailprice`, `p_comment` FROM `part` AS `part` WHERE (`p_name` LIKE ?)")                                                                                                                                 |
| HitCache:true                                                                                                                                                                                                                                                                                                                                                  |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
8 行 (0.01 秒)

HitCache:true と ParallelBKAJoin によって、PolarDB-Xではヒントワードが不要で、常に固定の BKA 結合プランが使用されることを確認できます。