PolarDB-X 1.0 は実行計画をキャッシュおよび管理することで、繰り返し実行されるクエリに対するオプティマイザーのオーバーヘッドを削減し、バージョンアップグレード後も複雑なクエリプランの安定性を維持します。
前提条件
開始する前に、以下が準備できていることを確認してください。
PolarDB-X 1.0 インスタンス
インスタンスに接続された MySQL 互換クライアントへのアクセス
仕組み
PolarDB-X 1.0 が SQL ステートメントを受信すると、次のプロセスが実行されます。
SQL ステートメントのパラメーター化。すべての定数がプレースホルダー (
?) に置き換えられ、パラメーターリストが作成されます。プランキャッシュの確認。パラメーター化された SQL がキャッシュキーとして使用されます。一致する実行計画が存在する場合は再利用されます。存在しない場合は、オプティマイザーが新しいプランを生成します。
シンプルなクエリ:直接実行。シンプルなクエリはプラン管理をスキップして即座に実行されます。
複雑なクエリ:プラン管理の適用。ベースラインに永続的に保存されているプランが使用されます。複数のプランが存在する場合、コストが最も低いものが選択されます。

基本概念
プランキャッシュ
プランキャッシュはデフォルトで有効になっています。各 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 | 完全なプランツリー。Gather、ParallelHashJoin、LogicalView などのオペレーターを表示します。 |
FIXED | 1 このプランが固定されており、CBO コストに関係なく常に使用される場合。0 このプランがコストに基づいて他のプランと競合する場合。 |
ACCEPTED | 1 プランが実行可能な場合。 |
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:trueBASELINE 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: 1FIXED=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 を実行し、ベースラインエントリを削除した後に再度実行します。