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

PolarDB:実行計画の管理

最終更新日:Mar 29, 2026

PolarDB-X 1.0 は実行計画をキャッシュおよび管理することで、繰り返し実行されるクエリに対するオプティマイザーのオーバーヘッドを削減し、バージョンアップグレード後も複雑なクエリプランの安定性を維持します。

前提条件

開始する前に、以下が準備できていることを確認してください。

  • PolarDB-X 1.0 インスタンス

  • インスタンスに接続された MySQL 互換クライアントへのアクセス

仕組み

PolarDB-X 1.0 が SQL ステートメントを受信すると、次のプロセスが実行されます。

  1. SQL ステートメントのパラメーター化。すべての定数がプレースホルダー (?) に置き換えられ、パラメーターリストが作成されます。

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

  3. シンプルなクエリ:直接実行。シンプルなクエリはプラン管理をスキップして即座に実行されます。

  4. 複雑なクエリ:プラン管理の適用。ベースラインに永続的に保存されているプランが使用されます。複数のプランが存在する場合、コストが最も低いものが選択されます。

Process of execution plans

基本概念

プランキャッシュ

プランキャッシュはデフォルトで有効になっています。各 SQL ステートメントをパラメーター化し (定数を ? に置き換える)、結果の実行計画をキャッシュします。同じクエリパターンが後続で実行されると、PolarDB-X 1.0 は最適化をスキップし、キャッシュされたプランを再利用します。

クエリがプランキャッシュにヒットしたかどうかを確認するには、ステートメントに対して EXPLAIN を実行し、HitCache フィールドを確認します。

  • HitCache:true — プランはキャッシュから提供されました。

  • HitCache:false — オプティマイザーが新しいプランを生成しました (キャッシュがバイパスされたか、まだ生成されていませんでした)。

プラン管理とベースライン

プラン管理は、プランキャッシュを通過する複雑なクエリを処理します。各パラメーター化された SQL ステートメントは 1 つのベースラインにマッピングされ、ベースラインには 1 つ以上の実行計画が保持されます。ベースライン内のプランはディスクに永続化され、バージョンアップグレード後も維持されます。

実行計画がプラン管理に入ると、SQL プラン管理 (SPM) は次のように評価します。

  • プランが既知の場合、SPM はそのコストが利用可能なプランの中で最小であるかどうかを確認します。

  • プランが未知の場合、SPM はその最適化の度合いを評価するために実行するかどうかを決定します。

ベースラインに複数のプランが存在する場合、SPM はコストが最も低いプランを選択します。自動プラン展開中、SPM はデータの変更後やバージョンアップグレード後にコストベースオプティマイザー (CBO) によって発見されたより良いプランをベースラインに追加します。

BASELINE LIST の出力フィールド

BASELINE LIST を使用して、現在のすべてのベースラインを表示します。出力には次のカラムが含まれます。

カラム説明
BASELINE_IDパラメーター化された SQL から派生した、ベースラインの一意の識別子。
PARAMETERIZED_SQLパラメーター化された SQL テンプレート (定数が ? に置き換えられています)。
PLAN_IDベースライン内の実行計画の一意の識別子。
EXTERNALIZED_PLAN完全なプランツリー。GatherParallelHashJoinLogicalView などのオペレーターを表示します。
FIXED1 このプランが固定されており、CBO コストに関係なく常に使用される場合。0 このプランがコストに基づいて他のプランと競合する場合。
ACCEPTED1 プランが実行可能な場合。

BASELINE コマンド

PolarDB-X 1.0 は、実行計画を管理するために次のコマンドを提供します。

BASELINE (LOAD|PERSIST|CLEAR|VALIDATE|LIST|DELETE) [<baseline_id>, ...]
BASELINE (ADD|FIX) SQL <hint> <select_statement>
コマンド説明
BASELINE ADD SQL <hint> <sql>指定された SQL ステートメントのベースラインに実行計画 (ヒントを使用して生成) を追加します。新しいプランは既存のプランと共存し、CBO がコストに基づいて選択します。
BASELINE FIX SQL <hint> <sql>実行計画を固定します。固定されたプランは常に使用され、CBO のコスト選択をバイパスします。
BASELINE LISTすべてのベースラインとそれに関連する実行計画をリスト表示します。
BASELINE LOAD指定されたベースラインをシステムテーブルからメモリにロードします。
BASELINE LOAD_PLAN指定された実行計画をシステムテーブルからメモリにロードします。
BASELINE PERSIST指定されたベースラインをディスクにフラッシュします。
BASELINE PERSIST_PLAN指定された実行計画をディスクにフラッシュします。
BASELINE CLEAR指定されたベースラインをメモリから削除します。
BASELINE CLEAR_PLAN指定された実行計画をメモリから削除します。
BASELINE DELETE指定されたベースラインをディスクから削除します。
BASELINE DELETE_PLAN指定された実行計画をディスクから削除します。

実行計画のチューニング

このワークフローは、オプティマイザーのデフォルトプランが最適ではない場合に使用します。例えば、データ分布の変更後や、アプリケーションコードを直接変更してヒントを追加できない場合などです。

次の例では、lineitem テーブルと part テーブルに対する JOIN クエリを使用します。

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

ステップ 1:現在のプランの確認

EXPLAIN を実行して、アクティブな実行計画を確認します。

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

出力は、プランが ParallelHashJoin を使用し、HitCache:true であることを示しており、プランがプランキャッシュから提供されたことを確認できます。

Gather(parallel=true)
  ParallelHashJoin(condition="l_partkey = p_partkey", type="inner")
    LogicalView(tables="[00-03].lineitem", ...)
    LogicalView(tables="[00-03].part", ..., sql="... WHERE (`p_name` LIKE ?)", ...)
HitCache:true

BASELINE LIST を実行して、このステートメントに対してプランが 1 つしか存在しないことを確認します。

mysql> BASELINE LIST;
+-------------+---------------------------------------------+-----------+-------------------+-------+----------+
| BASELINE_ID | PARAMETERIZED_SQL                           | PLAN_ID   | EXTERNALIZED_PLAN | FIXED | ACCEPTED |
+-------------+---------------------------------------------+-----------+-------------------+-------+----------+
| -399023558  | SELECT * FROM lineitem JOIN part ON ...     | -935671684| Gather(...)       |     0 |        1 |
+-------------+---------------------------------------------+-----------+-------------------+-------+----------+

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

特定のデータ条件下で Batched Key Access (BKA) JOIN のパフォーマンスが向上する場合、ベースラインにコミットする前に、ヒント付きで EXPLAIN を実行してテストします。

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

出力は、プランが ParallelBKAJoin に切り替わったことを確認します。HitCache:false であることに注意してください。これは、ヒントがプランキャッシュをバイパスしたことを意味します。

Gather(parallel=true)
  ParallelBKAJoin(condition="l_partkey = p_partkey", type="inner")
    LogicalView(tables="[00-03].lineitem", ...)
    Gather(concurrent=true)
      LogicalView(tables="[00-03].part", ...)
HitCache:false

ヒントはこの 1 回の実行で JOIN アルゴリズムを変更しますが、ベースラインには影響しません。

ステップ 3:ベースラインへの代替プランの追加

CBO がコストに基づいて選択できるように BKA JOIN プランを利用可能にするには、それをベースラインに追加します。

mysql> 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     |
+-------------+--------+

再度 BASELINE LIST を実行して、両方のプランがベースラインにあることを確認します (両方とも FIXED=0 であり、CBO がコストに基づいて選択することを意味します)。

mysql> BASELINE LIST;
+-------------+--------------------+-------------+--------------------------------------+-------+----------+
| BASELINE_ID | PARAMETERIZED_SQL  | PLAN_ID     | EXTERNALIZED_PLAN                    | FIXED | ACCEPTED |
+-------------+--------------------+-------------+--------------------------------------+-------+----------+
| -399023558  | SELECT * FROM ...  | -1024543942 | Gather > ParallelBKAJoin > ...       |     0 |        1 |
| -399023558  | SELECT * FROM ...  | -935671684  | Gather > ParallelHashJoin > ...      |     0 |        1 |
+-------------+--------------------+-------------+--------------------------------------+-------+----------+

ステップ 4:プランの固定 (任意)

CBO のコスト見積もりに関係なく、PolarDB-X 1.0 に常に BKA JOIN プランを使用させるには (例えば、バージョンアップグレード後のプランリグレッションを防ぐため)、BASELINE FIX を使用します。

mysql> 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     |
+-------------+--------+

BASELINE LIST を実行して、BKA JOIN プランの FIXED=1 を確認します。

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", ...)
    Gather(concurrent=true)
      LogicalView(tables="[00-03].part", ...)
            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", ...)
    LogicalView(tables="[00-03].part", ...)
            FIXED: 0
         ACCEPTED: 1

FIXED=1 が設定されていると、ヒントがなくても、このクエリパターンのすべての実行で BKA JOIN プランが使用されます。

mysql> 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", ...)
    Gather(concurrent=true)
      LogicalView(tables="[00-03].part", ...)
HitCache:true
固定されたプランを削除して CBO に再度選択させるには、BASELINE DELETE <baseline_id> でベースラインエントリを削除するか、BASELINE CLEAR <baseline_id> でメモリからクリアします。

バージョンアップグレード前のプランリグレッションの防止

バージョンアップグレードにより、CBO が異なる実行計画を選択する可能性があり、クエリのパフォーマンスに影響を与えることがあります。アップグレード前に安定して良好なパフォーマンスを発揮するプランを保護するには、ステップ 4 で説明されているように BASELINE FIX を使用してプランを固定します。

現在どのプランが固定されているかを確認するには、次を実行します。

mysql> BASELINE LIST\G

出力で FIXED: 1 となっているプランは固定されており、アップグレード後も変更されません。アップグレード後、固定されたプランを確認し、不要になったものを削除します。

-- 固定されたプランを削除して CBO に再度自由に選択させる
BASELINE DELETE <baseline_id>;

固定を解除する前後のプランの動作を比較するには、プランが固定されている間 (FIXED=1) に同じクエリで EXPLAIN を実行し、ベースラインエントリを削除した後に再度実行します。