OceanBaseデータベースのオプティマイザーは、クエリを解析処理する際、クエリの構造に基づいて複数のクエリブロック(Query Block)に分解します。各ブロックには一意のクエリブロック名(Query Block Name、略称QB Name)が付与されます。手動で指定しない場合、オプティマイザーが自動的にQB Nameを生成します。
QB_NAMEヒントの構文とルール
QB_NAMEヒントを使用して、クエリブロックにQB Nameを明示的に割り当てることができます。構文は以下のとおりです:
/*+ QB_NAME(qb_name) */
以下の例では、外部クエリブロックは qb1、インラインビュー(ビュー view_1 内)は qb2 と命名されています:
SELECT /*+ QB_NAME(qb1) */ * FROM (SELECT /*+ QB_NAME(qb2) */ * FROM t1) view_1;
使用上の注意点:
- QB Nameは大文字小文字を区別しません。
- QB Nameには特殊文字を含めることはできません。
- QB Nameの長さは最大20文字に制限されます。
- 同一クエリブロックに複数のQB Nameを割り当てたり、異なるブロックで同じQB Nameを使用したりすることはできません。
クエリブロック名の使用方法
クエリブロックヒントの作用範囲の定義
クエリブロックヒントでは、ヒント内でクエリブロック名を指定することで、その作用範囲を定義できます。
以下の例のように、ヒント index(@qb2 t1 idx) はクエリブロック qb1 内で宣言されていますが、クエリブロック qb2 内で有効になるよう指定されています:
SELECT /*+ INDEX(@qb2 t1 idx) QB_NAME(qb1) */ * FROM (SELECT /*+ NO_MERGE QB_NAME(qb2) */ * FROM t1) view_1;
クエリ内のヒントの作用対象の指定
クエリ内のヒントの作用対象を指定することで、クエリ内のヒントの対象を正確に制御できます。
ヒント内でクエリブロック名を使用することで、作用対象を正確に指定できます。
以下の例のように、leading ヒントを使用する場合、テーブルのクエリブロック名を明示的に指定しないと、ヒントが無効になる可能性があります:
SELECT /*+ LEADING(t1@sel$1 t1@sel$2) */ * FROM t1, (SELECT * FROM t1) v WHERE t1.c2 = v.c2;
Query Plan
===========================
|ID|OPERATOR |NAME|
---------------------------
|0 |HASH JOIN | |
|1 |├─TABLE FULL SCAN|t1 |
|2 |└─TABLE FULL SCAN|t1 |
===========================
クエリブロック名の自動生成ルール
QB Nameが指定されていない場合、オプティマイザーは以下の形式でクエリブロック名を自動生成します:
query_block_type_str$idx
ここで、query_block_type_str$ はクエリブロックタイプを識別する文字列であり、idx はそのクエリブロックを識別する番号です。
次の表は、異なるタイプのクエリブロックに自動生成される名前の例を示しています:
クエリブロック |
例 |
|---|---|
| SELECT | SEL$1 |
| UNION ALL/UNION/INTERSECT/MINUS | SET$1 |
| INSERT | INS$1 |
| UPDATE | UPD$1 |
| DELETE | DEL$1 |
| MERGE | MRG$1 |
| REPLACE | REP$1 |
| INSERT ALL | INS_ALL$1 |
以下の例のように、UNION はオプティマイザーがこれらの操作を含むクエリブロックに対して自動的にクエリブロック名を生成する原因となります。例えば、UNION を使用するクエリでは、そのクエリブロックは自動的に SET$1 と命名されます:
SELECT /*+ USE_HASH_SET(@SET$1) */ c1, c2 FROM t1
UNION
SELECT c1, c2 FROM t2;
この例では、Hint /*+USE_HASH_SET(@SET$1) */ がオプティマイザーに UNION 操作に HASH DISTINCT SET アルゴリズムを使用するよう指示しています。
複雑なクエリにおけるクエリブロック名
より複雑なクエリを解析する際、オプティマイザーは外側から内側への順序で各クエリブロックに連番を割り当てます。手動で指定した QB_NAME Hint を削除すると、自動生成されるクエリブロック名は以下のようになります:
SELECT /*+ QB_NAME(qb1) */ * FROM (SELECT /*+ QB_NAME(qb2) */ * FROM t1) v;
QB_NAME Hint を削除すると、外側のクエリブロック qb1 の自動生成名は SEL$1 となり、内側のブロック qb2 の名前は SEL$2 となります。
クエリのリライトとクエリブロック名の変化
クエリブロックがクエリのリライトをトリガーすると、そのクエリブロック名は変更される可能性があります。EXPLAIN EXTENDED コマンドを使用すると、クエリプランの qb name trace でこれらの変化を追跡できます。
クエリのリライト前の自動生成されたクエリブロック名を確認するには、クエリに NO_QUERY_TRANSFORMATION Hint を含めてすべてのクエリのリライトを禁止し、その後 EXPLAIN OUTLINE を使用して OUTLINE DATA を取得します。OUTLINE DATA の FULL、INDEX などのクエリブロック Hint を分析することで、各クエリブロックの名前を検証できます。
例えば、このクエリでは OUTLINE DATA の FULL(@"SEL$2" "test"."t1"@"SEL$2") が、インラインビュー v 内のクエリブロック名が SEL$2 であることを示しています:
SELECT /*+ NO_QUERY_TRANSFORMATION */ COUNT(*)
FROM (SELECT * FROM t1) v GROUP BY c1;