OceanBaseデータベースは CREATE OUTLINE ステートメントを使用してSQLステートメントと特定の実行計画をバインドし、そのSQLが以降の実行時に常に指定された実行計画を使用するよう保証します。これにより、オプティマイザーの選択が不適切であることによるパフォーマンスの変動を回避できます。OceanBaseデータベースの CREATE OUTLINE は、以下のプランバインドモードをサポートしています:
- 厳密バインド:特定のSQLステートメントと特定の実行計画を一対一でバインドします。単一データベース・単一テーブルのチューニングシナリオに適しています。
- テンプレートバインド:
BINDING_RULE句を使用してアウトラインをテンプレート化し、パターンに合致する複数のSQL(例えば、データベースやテーブルのシャーディングシナリオでの類似した複数のSQL)に同時に適用します。データベースやテーブルのシャーディング、SaaSマルチテナントなどのシナリオに適しています。
既に稼働中の業務において、オプティマイザーが選択した計画が十分に最適化されていない場合、オンラインでプランのバインドを行うことができます。つまり、業務側でSQLを変更する必要はなく、DDL操作を通じて一連のHintをSQLに追加することで、オプティマイザーが指定されたHintのセットに基づいて、そのSQLに対してより優れた計画を生成するようにします。このHintのセットをアウトラインと呼びます。
Outlineビュー
Outlineビューは DBA_OB_OUTLINES で、そのフィールド説明は以下の表のとおりです。
フィールド名 |
タイプ(MySQLモード) |
タイプ(Oracleモード) |
説明 |
|---|---|---|---|
| CREATE_TIME | TIMESTAMP(6) | TIMESTAMP(6) | 作成タイムスタンプ |
| MODIFY_TIME | TIMESTAMP(6) | TIMESTAMP(6) | 変更タイムスタンプ |
| TENANT_ID | BIGINT(20) | NUMBER(38) | テナントID |
| DATABASE_ID | BIGINT(20) | NUMBER(38) | データベースID |
| OUTLINE_ID | BIGINT(20) | NUMBER(38) | Outline ID |
| DATABASE_NAME | VARCHAR2(128) | VARCHAR2(128) | データベース名 |
| OUTLINE_NAME | VARCHAR2(128) | VARCHAR2(128) | Outline名 |
| VISIBLE_SIGNATURE | LONGTEXT | CLOB | Signatureの逆シリアライズ結果。Signature情報を確認しやすくするために使用されます。 |
| SQL_TEXT | LONGTEXT | CLOB | Outline作成時に ON 句で指定されたSQLです。 |
| OUTLINE_TARGET | LONGTEXT | CLOB | Outline作成時に TO 句で指定されたSQLです。 |
| OUTLINE_SQL | LONGTEXT | CLOB | 完全なOutline情報を持つSQL |
| SQL_ID | VARCHAR2(32) | VARCHAR2(32) | SQL識別子 |
| OUTLINE_CONTENT | LONGTEXT | CLOB | 完全な実行計画Outline情報 |
| PATTERN_RULES | LONGTEXT | CLOB | テンプレートOutlineのMAPルールで、JSON形式で保存されます。このフィールドが空でない場合はテンプレートOutlineを示し、空の場合は厳密Outlineを示します。 |
厳密バインディング
厳密バインディングは、OceanBaseの既存の計画バインディング機能であり、SQL_TEXTまたはSQL_IDを使用して特定のSQLと特定の実行計画を一対一でバインドします。BINDING_RULEを指定しないOutlineの動作は、過去のバージョンと完全に一致します。
SQL_TEXTを使用したOutlineの作成
SQL_TEXTを使用してOutlineを作成すると、Key-Valueペアが生成され、Mapに格納されます。ここで、KeyはバインドされたSQLのパラメータ化後のテキスト、ValueはバインドされたHintです。具体的なパラメータ化の原則については、クイックパラメータ化を参照してください。
SQL_TEXTを使用してOutlineを作成する構文は以下のとおりです:
CREATE [OR REPLACE] OUTLINE <outline_name> ON <stmt> [ TO <target_stmt> ];
説明は以下のとおりです:
OR REPLACEを指定すると、既存の実行計画を置き換えることができます。ここで、
stmtは通常、Hintと元のパラメータを含むDMLステートメントです。TO target_stmtを指定しない場合、データベースが受け付けたSQLをパラメータ化したテキストと、stmtからHintを除去してパラメータ化したテキストが一致すれば、そのSQLにstmt内のHintをバインドして実行計画を生成します。Hintを含むステートメントに対して固定の計画を実行したい場合は、元のSQLを指定するために
TO target_stmtが必要です。例:
obclient> CREATE OUTLINE outline1 ON SELECT /*+NO_REWRITE*/ * FROM tbl1 WHERE col1 = 4 AND col2 = 6 ORDER BY 2 TO SELECT * FROM tbl1 WHERE col1 = 4 AND col2 = 6 ORDER BY 2;注意
target_stmtを使用する場合、stmtとtarget_stmtがHintを除去した後、完全に一致することが厳密に要求されます。
以下の例では、オプティマイザーは主キースキャンを選択しました。データ量が増加した場合、インデックス idx_c2 を使用すると、このSQLはより最適化されます。この時、アウトラインを作成してこのSQLにインデックス計画をバインドし、実行できます。
obclient> CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT, c3 INT, INDEX idx_c2(c2));
Query OK, 0 rows affected
obclient> INSERT INTO t1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3);
Query OK, 1 rows affected
obclient> EXPLAIN SELECT * FROM t1 WHERE c2 = 1;
Query Plan:
===================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
-----------------------------------
|0 |TABLE SCAN|t1 |1 |37 |
===================================
Outputs & filters:
-------------------------------------
0 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c2 = 1]),
access([t1.c2], [t1.c1], [t1.c3]), partitions(p0)
以下のSQL文に基づいてアウトラインを作成します:
obclient> CREATE OUTLINE otl_idx_c2
ON SELECT/*+ INDEX(t1 idx_c2)*/ * FROM t1 WHERE c2 = 1;
Query OK, 0 rows affected
SQL_IDを使用してアウトラインを作成する
SQL_ID を使用してアウトラインを作成する構文は以下のとおりです:
obclient> CREATE OUTLINE outline_name ON sql_id USING HINT hint_text;
SQL_ID はバインドするSQLに対応する SQL_ID であり、以下の方法で取得できます:
V$OB_PLAN_CACHE_PLAN_STATをクエリすることで取得します。GV$OB_SQL_AUDITをクエリすることで取得します。パラメータ化された元のSQLを使用して、MD5で
SQL_IDを生成します。以下のスクリプトを参照して、対応するSQLのSQL_IDを生成できます。IMPORT hashlib sql_text='SELECT * FROM t1 WHERE c2 = ?' sql_id=hashlib.md5(sql_text.encode('utf-8')).hexdigest().upper() PRINT(sql_id)
SQL_ID を使用してアウトラインをバインドします。以下の例を参照してください:
obclient> CREATE OUTLINE otl_idx_c2 ON 'ED570339F2C856BA96008A29EDF04C74'
USING HINT /*+ INDEX(t1 idx_c2)*/ ;
注意
- Hintの形式は
/*+ xxx */です。Hintの説明に関する詳細は、Optimizer Hint を参照してください。 SQL_TEXT方式で作成されたアウトラインは、SQL_ID方式で作成されたアウトラインを上書きします。SQL_TEXT方式の優先順位が高いです。SQL_IDに対応するSQL文にすでにHintがある場合、アウトラインの作成時に指定したHintが、元のSQL文のすべてのHintを上書きします。
アウトラインデータ
アウトラインデータは、オプティマイザーが特定の実行計画を完全に再現するために生成される一連のHint情報であり、BEGIN_OUTLINE_DATA で始まり、END_OUTLINE_DATA で終わります。
アウトラインデータは、EXPLAIN EXTENDED コマンドで取得できます。以下の例を参照してください:
obclient> EXPLAIN EXTENDED SELECT/*+ index(t1 idx_c2)*/ * FROM t1 WHERE c2 = 1;
Query Plan:
| =========================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
-----------------------------------------
|0 |TABLE SCAN|t1(idx_c2)|1 |88 |
=========================================
Outputs & filters:
-------------------------------------
0 - output([t1.c1(0x7ff95ab37448)], [t1.c2(0x7ff95ab33090)], [t1.c3(0x7ff95ab377f0)]), filter(nil),
access([t1.c2(0x7ff95ab33090)], [t1.c1(0x7ff95ab37448)], [t1.c3(0x7ff95ab377f0)]), partitions(p0),
is_index_back=true,
range_key([t1.c2(0x7ff95ab33090)], [t1.c1(0x7ff95ab37448)]), range(1,MIN ; 1,MAX),
range_cond([t1.c2(0x7ff95ab33090) = 1(0x7ff95ab309f0)])
Used Hint:
-------------------------------------
/*+
INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
*/
Outline Data:
-------------------------------------
/*+
BEGIN_OUTLINE_DATA
INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
END_OUTLINE_DATA
*/
Plan Type:
-------------------------------------
LOCAL
Optimization Info:
-------------------------------------
t1:table_rows:3, physical_range_rows:1, logical_range_rows:1, index_back_rows:1, output_rows:1, est_method:local_storage, optimization_method=cost_based, avaiable_index_name[idx_c2], pruned_index_name[t1]
level 0:
***********
paths(@1101710651081553(ordering([t1.c2], [t1.c1]), cost=87.951827))
その中のアウトラインデータ情報は以下のとおりです:
/*+
BEGIN_OUTLINE_DATA
INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
END_OUTLINE_DATA
*/
Outline DataもHintに属するため、プランのバインド処理中に使用できます。以下の例を参照してください:
obclient> CREATE OUTLINE otl_idx_c2
ON 'ED570339F2C856BA96008A29EDF04C74'
USING HINT /*+
BEGIN_OUTLINE_DATA
INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
END_OUTLINE_DATA
*/;
Query OK, 0 rows affected
テンプレートバインディング
テンプレートバインディングは、OceanBaseが新たに追加した実行計画のバインディング機能です。BINDING_RULE 句を使用してアウトラインをテンプレート化し、パターンに一致する複数のSQLに対して同時に適用できます。データベースやテーブルのシャーディング、SaaS型マルチテナントなど、同一モデルのデータが複数のテーブルやデータベースに分散しているシナリオに適しています。
BINDING_RULE構文
テンプレートアウトラインを作成する構文は以下のとおりです:
CREATE [OR REPLACE] OUTLINE outline_name ON stmt
BINDING_RULE (binding_item);
binding_item:
SCOPE = {DATABASE | TENANT}
| MAP = {real_name TO 'pattern', ...}
パラメータの説明は以下のとおりです:
OR REPLACE:オプションです。OR REPLACEを指定すると、既存の実行計画を置き換えることができます。outline_name:作成するアウトライン名を指定します。stmt:一般的には、ヒントと元のパラメータを持つDMLステートメントです。BINDING_RULE (binding_item):このアウトラインの適用レベルを指定するために使用されます。説明
V4.4.2バージョンでは、V4.4.2 BP3バージョンから
BINDING_RULE句が導入されました。SCOPE = {DATABASE | TENANT}:SCOPE = DATABASE:デフォルト値で、現在のデータベースでのみ有効であることを意味します。SCOPE = TENANT:現在のテナント内のすべてのデータベースで有効であることを意味します。
MAP = {real_name TO 'pattern', ...}:テーブル名/データベース名のワイルドカードルールを指定します。左側は実際のテーブル名またはdb.tableの形式で、右側はpatternです。patternには${変数名}または${変数名:正規表現}を記述できます。注意
${var}または${var:regex}:varという名前の変数を定義し、正規表現パターンを指定することができます。正規表現が指定されていない場合、デフォルトで任意の非空文字列に一致します。MAPの左側がdb.tableの形式の場合、右側のpatternではデータベース名とテーブル名のパターンをそれぞれ単一引用符で囲み、ドットで区切る必要があります:'db_pattern'.'table_pattern'。- 同一の
BINDING_RULE内では、変数は定義後に参照する必要があります。同名の変数は、すべての参照箇所で値が一致している必要があります。
四種類の典型的なバインディングモード
モード |
SCOPE |
MAP |
適用シナリオ |
|---|---|---|---|
| 厳密バインディング | DATABASE(デフォルト) | 空 | 単一データベース・単一テーブル(既存の動作) |
| 現在のデータベース内のシャードテーブルのワイルドカード指定 | DATABASE | テーブル名のみをワイルドカードで指定 | 単一データベース内の orders_001 … orders_127 などのシャードテーブル |
| データベースをまたいだ厳密なテーブル名 | TENANT | 空 | データベースをまたいだ同名テーブル、例えば db_001.orders、db_002.orders |
| データベースをまたいだワイルドカード | TENANT | db.table を含むワイルドカード |
データベース名 + テーブル名の組み合わせによるワイルドカード |
データベースをまたいだ同名テーブルのバインディング
データベースシャーディングアーキテクチャでは、複数のデータベースに同名のテーブル(例えば db_001.orders、db_002.orders)が存在することがあります。SCOPE = TENANT を使用すると、一つのアウトラインですべてのデータベースの同名テーブルをカバーできます。
例:
すべてのデータベースの orders テーブルは idx_status インデックスを使用します:
obclient> CREATE OUTLINE otl_orders
ON SELECT /*+ index(orders, idx_status) */*
FROM orders
WHERE status = 'a'
BINDING_RULE (SCOPE = TENANT);
データベース
db_001でのクエリヒット例。obclient> USE db_001;obclient> SELECT * FROM orders WHERE status = 'pending';データベース
db_002でのクエリヒット例。obclient> USE db_002;obclient> SELECT * FROM orders WHERE status = 'pending';データベース
db_testでのクエリヒット例。obclient> USE db_test;obclient> SELECT * FROM orders WHERE status = 'pending';
現在のデータベース内のシャードテーブルのワイルドカード指定
シャーディングアーキテクチャでは、単一のデータベース内に一定の命名規則に従う複数のシャードテーブル(例:orders_sh、orders_hz、orders_bj)が存在します。MAP を正規表現変数と組み合わせることで、1つのアウトラインですべてのシャードテーブルをカバーできます。
例:
orders_xx シリーズのシャードテーブルは同じアウトラインを共有します:
obclient> CREATE OUTLINE otl_orders_tpl
ON SELECT /*+ index(orders_sh, idx_status) */*
FROM orders_sh
WHERE status = 'a'
BINDING_RULE (MAP = {orders_sh TO 'orders_${S:[a-z]+}'});
クエリヒット例
S=bj。obclient> SELECT * FROM orders_bj WHERE status = 'pending';クエリヒット例
S=hz。obclient> SELECT * FROM orders_hz WHERE status = 'pending';クエリミス例。
001は[a-z]+に一致しません。obclient> SELECT * FROM orders_001 WHERE status = 'pending';
データベース名 + テーブル名の組み合わせによるワイルドカード
データベースとテーブルを組み合わせて分割したアーキテクチャ(例:db_001.orders_sh、db_002.orders_bj)では、データベース名とテーブル名の両方に対してワイルドカードを使用できます。
例:
db_数字 パターンのデータベースと orders_英字 パターンのテーブルにのみ有効です:
obclient> CREATE OUTLINE otl_full
ON SELECT *
FROM db_001.orders_sh
WHERE status = 'a'
BINDING_RULE (
SCOPE = TENANT,
MAP = {db_001.orders_sh TO 'db_${D:[0-9]+}'.'orders_${S:[a-z]+}'}
);
クエリヒットの例。
obclient> SELECT * FROM db_002.orders_bj WHERE status = 'pending';クエリミスの例、データベース名が一致しません。
obclient> SELECT * FROM test_db.orders_sh WHERE status = 'pending';
特定のデータベース内のすべてのテーブルをカバーする場合は、汎用正規表現 ${T:.*} を使用できます:
obclient> CREATE OUTLINE otl_db_all
ON SELECT *
FROM db_001.orders
WHERE status = 'a'
BINDING_RULE (
SCOPE = TENANT,
MAP = {db_001.orders TO 'db_${D:[0-9]+}'.'${T:.*}'}
);
複数テーブルJOINと変数一貫性制約
複数テーブルの JOIN シナリオでは、JOIN の対象となる複数のテーブルがすべてシャーディングされている場合、同じ変数が参照されるすべての箇所で一貫した値を持つことを保証する必要があります。これにより、誤ったテーブルの組み合わせマッチング(例:orders_hz JOIN products_bj)を防ぎます。
同一の MAP 内で同じ変数名を使用することで、一貫性制約を実現できます。
例:
orders_${S} と products_${S} の S は同じでなければなりません。
obclient> CREATE OUTLINE otl_join
ON SELECT /*+ use_nl(orders_sh) */o.*, p.*
FROM orders_sh o JOIN products_sh p
ON o.id = p.order_id
BINDING_RULE (
MAP = {
orders_sh TO 'orders_${S:[a-z]+}',
products_sh TO 'products_${S}'
}
);
クエリヒットの例、
S=hz、orders_hz JOIN products_hz。obclient> SELECT o.*, p.* FROM orders_hz o JOIN products_hz p ON o.id = p.order_id;クエリミスの例、
ordersのS=hz、productsのS=bj、変数が一致しないため、自動的にミスとなります。obclient> SELECT o.*, p.* FROM orders_hz o JOIN products_bj p ON o.id = p.order_id;
スコープとマッチング優先順位
スコープ
DATABASE(デフォルト):アウトラインは現在のデータベース内でのみ有効です。アウトラインを作成したデータベースがスコープデータベースとなります。TENANT:アウトラインは現在のテナント内のすべてのデータベースで有効です。作成時は引き続き特定のデータベースでCREATE OUTLINEを実行する必要がありますが、スコープはテナント全体に拡張されます。
マッチング優先順位
同一のSQLが複数のアウトラインにマッチする可能性がある場合、OceanBaseデータベースは以下の優先順位で高いものから低いものへとマッチングを試みます:
- 現在のデータベースの厳密な
signature:厳密に一致するSQLパラメータ化テキスト。 - 現在のデータベースの
sql_id:SQL_IDで作成されたアウトライン。 format outline:TO target_stmtを含むアウトライン。- 現在のデータベーステンプレート:
SCOPE = DATABASEのテンプレートアウトライン。 - データベース間(テナント内)テンプレート:
SCOPE = TENANTのテンプレートアウトライン。
現在のデータベーステンプレートはデータベース間テンプレートよりも優先順位が高く、曖昧さは生じません。
作成したOutlineが有効かどうかを確認する
Outlineが正常に作成され、期待どおりに機能するかを検証する必要があります。厳密OutlineとテンプレートOutlineの検証方法は若干異なります。
厳密Outlineの検証
厳密Outlineが有効になっているかを確認するには、以下の3つのステップで検証します:
Outlineが正常に作成されたことを確認します。
DBA_OB_OUTLINESビューを確認し、対応する名前のOutlineが正常に作成されたかどうかを確認します。obclient> SELECT * FROM DBA_OB_OUTLINES WHERE OUTLINE_NAME = 'otl_idx_c2'\G *************************** 1. row *************************** tenant_id: 1001 database_id: 1100611139404776 outline_id: 1100611139404777 database_name: test outline_name: otl_idx_c2 visible_signature: SELECT * FROM t1 WHERE c2 = ? sql_text: SELECT/*+ index(t1 idx_c2)*/ * FROM t1 WHERE c2 = 1 outline_target: outline_sql: SELECT /*+ BEGIN_OUTLINE_DATA INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2") END_OUTLINE_DATA*/* FROM t1 WHERE c2 = 1新しいSQLの実行時に、バインドされたOutlineに基づいて新しい実行計画が生成されたかどうかを確認します。
OutlineにバインドされたSQLで新しいクエリを実行した後、
GV$OB_PLAN_CACHE_PLAN_STATテーブルのそのSQLに対応する計画情報のoutline_idを確認します。outline_idがDBA_OB_OUTLINESで確認したoutline_idと同じ場合、バインドされたOutlineに従って生成された実行計画であることを意味し、そうでない場合はそうではありません。obclient> SELECT SQL_ID, PLAN_ID, STATEMENT, OUTLINE_ID, OUTLINE_DATA FROM oceanbase.GV$OB_PLAN_CACHE_PLAN_STAT WHERE STATEMENT LIKE '%SELECT * FROM t1 WHERE c2 =%'\G *************************** 1. row *************************** sql_id: ED570339F2C856BA96008A29EDF04C74 plan_id: 17225 statement: SELECT * FROM t1 WHERE c2 = ? outline_id: 1100611139404777 outline_data: /*+ BEGIN_OUTLINE_DATA INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2") END_OUTLINE_DATA*/生成された実行計画が期待通りであるかどうかを確認します。
バインドされたOutlineによって生成された計画であることを確認した後、生成された計画が期待通りであるかどうかを確認する必要があります。
GV$OB_PLAN_CACHE_PLAN_EXPLAINテーブルをクエリして、plan_cacheにキャッシュされた実行計画の形を確認することができます。具体的な確認方法については、以下を参照してください。obclient> SELECT OPERATOR, NAME FROM oceanbase.GV$OB_PLAN_CACHE_PLAN_EXPLAIN WHERE TENANT_ID = 1001 AND SVR_IP = '10.XXX.XXX.XXX' AND SVR_PORT = 30474 AND PLAN_ID = 17225; +--------------------+------------+ | OPERATOR | NAME | +--------------------+------------+ | PHY_ROOT_TRANSMIT | NULL | | PHY_TABLE_SCAN | t1(idx_c2) | +--------------------+------------+
テンプレートOutlineの検証
テンプレートOutlineの検証方法は厳密Outlineと類似していますが、以下の点に注意する必要があります:
テンプレートOutlineが正常に作成されたことを確認します。
DBA_OB_OUTLINESビューのpattern_rulesフィールドを確認し、テンプレートOutlineであるかどうかを確認します。pattern_rulesが空でない場合、テンプレートOutlineです。すべてのテンプレートOutlineを確認するには:obclient> SELECT outline_name, visible_signature, pattern_rules FROM oceanbase.DBA_OB_OUTLINES WHERE pattern_rules IS NOT NULL AND pattern_rules != '';SQLがテンプレートOutlineにヒットしたかどうかを確認します。
テンプレートOutlineにヒットすると、
GV$OB_PLAN_CACHE_PLAN_STATのoutline_idにも対応するOutlineのIDが設定されます (outline_idが0より大きい場合はヒットを意味します)。ヒットしたかどうかを確認するには:obclient> SELECT outline_id, outline_data FROM oceanbase.GV$OB_PLAN_CACHE_PLAN_STAT WHERE query_sql LIKE '%your_marker%' LIMIT 1;複数テーブルの検証。テンプレートOutlineについては、異なるシャーディングテーブルのSQLを使用して個別に検証し、すべての期待されるシャーディングテーブルが正しくテンプレートOutlineにヒットすることを確認することをお勧めします。
Outlineの削除
Outlineを削除すると、対応するSQLはバインドされたOutlineに基づいて実行計画を再生成しなくなります。
アウトラインを削除する構文は以下のとおりです:
DROP OUTLINE outline_name
[BINDING_RULE (binding_item)];
binding_item:
SCOPE = {DATABASE | TENANT}
パラメータの説明は以下のとおりです:
outline_name:削除するアウトライン名を指定します。BINDING_RULE (binding_item):オプションです。アウトラインの削除レベルを指定するために使用します。BINDING_RULE (SCOPE = DATABASE):デフォルト値です。現在のデータベースレベルのアウトラインを削除することを指定します(BINDING_RULEパラメータを指定しない場合と同等です)。BINDING_RULE (SCOPE = TENANT):指定された名前のデータベース間(テナントレベル)アウトラインを削除します。
説明
V4.4.2バージョンでは、V4.4.2 BP3バージョンから
BINDING_RULE句が導入されました。
注意
- 厳密アウトライン(
SCOPE = DATABASE)を削除する場合、対応するデータベースで実行するか、outline_nameにデータベース名を指定する必要があります。 - データベース間アウトライン(
SCOPE = TENANT)を削除する場合、任意のデータベースで実行できますが、BINDING_RULE(SCOPE = TENANT)を明示的に指定する必要があります。
プランバインディングと実行計画キャッシュの関係
SQL_TEXTを使用して厳密アウトラインを作成すると、SQLリクエストが新しい計画を生成してアウトラインを検索する際に使用するキーと、計画キャッシュが使用するキーは同じになります。つまり、どちらもSQLパラメータ化後のテキスト列です。テンプレートアウトラインは、Template Signatureを使用して候補をフィルタリングし、正規表現Patternの検証を通過した場合にヒットと判断します。テンプレートマッチング段階の追加オーバーヘッドは、主にASTレベルでのTemplate Signatureの生成と正規表現の検証によるものです。
厳密アウトラインの作成または削除時に、対応するSQLに新しいリクエストがあると、実行計画キャッシュ内の対応する実行計画が無効になり、バインドされたアウトラインに基づいて生成された実行計画に更新されます。
テンプレートアウトラインの作成または削除時には、そのテンプレートパターンに一致するすべてのSQLの計画キャッシュが無効になります。
アウトラインの作成または削除後、対応するSQLに新しいリクエストがあると、実行計画キャッシュ内の対応する実行計画が無効になり、バインドされたアウトラインに基づいて生成された実行計画に更新されます。
パフォーマンスへの影響
シナリオ |
複雑さ |
説明 |
|---|---|---|
| システム内にテンプレートアウトラインがない場合 | O(1) | has_template_outline ショートサーキットスイッチによりテンプレートマッチングパスがスキップされるため、テンプレートアウトラインのないテナントでは追加のオーバーヘッドが発生しません。 |
| 厳密アウトラインヒット | O(1) | 既存のハッシュマッチングを再利用するため、厳密バインドのパフォーマンスはテンプレートバインド機能の影響を受けません。 |
| テンプレートアウトラインマッチング | O(1) ハッシュ + n × O(T) Pattern検証 | n は同じシグネチャを持つ候補テンプレートの数、T はSQL内のテーブル数です。 |
| 変数一貫性検証 | O(V) | V は変数数で、通常は ≤ 3 です。 |
正規表現の長さは制限されており(≤128文字)、タイムアウトメカニズムも備えているため、病的な正規表現によるマッチングの遅延を防ぎます。
制限と注意事項
MAPにdb.table形式が含まれる場合、SCOPE = TENANTを明示的に指定する必要があります。そうでない場合、作成時にエラーが発生します。- 同一の
BINDING_RULE内で、各データベース名patternとテーブル名patternには最大1つの変数しか使用できません。複雑な式は複数のアウトラインに分割してください。 - 変数は定義後に参照する必要があります。同名の変数定義は1回だけ可能です。
db.*構文はサポートされていません。'db_${D:[0-9]+}'.'${T:.*}'などの等価表現を使用してください。- 正規表現は
POSIX拡張構文を採用しており、逆参照やゼロ幅アサーションなどの複雑な機能はサポートされていません。 SCOPE = DATABASEのみでMAPがない場合、アウトラインの動作は完全に変わらず、従来の厳密アウトラインと同等です。MAX_CONCURRENTスロットリング系アウトラインは、現在BINDING_RULEをサポートしていません。- テナント間のアウトラインバインディングはサポートされていません。
関連ドキュメント
Format Outline(CREATE FORMAT OUTLINE)はPSシナリオでも有効であり、マッチングルールはテキストプロトコルと一致します。詳細については、CREATE FORMAT OUTLINE(MySQLモード)およびCREATE FORMAT OUTLINE(Oracleモード)を参照してください。