ヒント機構により、オプティマイザーが指定された実行計画を生成するようにできます。
通常、オプティマイザーはユーザーのクエリに対して最適な実行計画を選択します。そのため、ユーザーがヒントを使用して指定する必要はありません。しかし、特定のシナリオでは、オプティマイザーが生成する実行計画がユーザーの要件を満たさない場合があります。このような場合、ユーザーはヒントを使用して特定の実行計画の生成を指示する必要があります。
ヒントの構文
構文的には、ヒントは特殊なSQLコメントですが、コメントの左側のマーカー("/*"記号)の後に「+」が付いています。コメントである以上、サーバー側がSQL文内のヒントを認識できない場合、オプティマイザーはユーザーのヒントを無視し、デフォルトの計画生成ロジックによってスキーマを作成することを選択します。また、ヒントはオプティマイザーが計画の論理構造を生成する方法にのみ影響を及ぼし、SQL文の意味には影響しません。
{ DELETE | INSERT | SELECT | UPDATE | REPLACE } /*+ [hint_text][,hint_text]... */
注意
MySQLのCクライアントを使用してヒントを含むSQL文を実行する場合は、-c オプションを使用してログインする必要があります。そうでない場合、MySQLクライアントはヒントをコメントとしてユーザーのSQL文から削除し、システムがユーザーのヒントを受信できなくなります。
ヒントパラメータ
ヒント関連のパラメータ名、意味、構文は次の表のとおりです。
名前 |
構文 |
意味 |
|---|---|---|
| NO_REWRITE | NO_REWRITE | SQLのリライトを禁止します。 |
| READ_CONSISTENCY | READ_CONSISTENCY (WEAK[STRONGFROZEN]) | 読み取りの一貫性の設定(弱/強)。 |
| INDEX_HINT | /*+ INDEX(table_name index_name) */ | テーブルのインデックスを設定します。 |
| QUERY_TIMEOUT | QUERY_TIMEOUT(INTNUM) | タイムアウト時間を設定します。 |
| LOG_LEVEL | LOG_LEVEL([']log_level[']) | ログレベルを設定します。モジュールレベルステートメントを設定する場合は、最初のシングルクォート(')で始め、2番目のシングルクォート(')で終えます。例:'DEBUG'。 |
| LEADING | LEADING([qb_name] TBL_NAME_LIST) | 結合順序を設定します。 |
| ORDERED | ORDERED | SQLの順序で結合するように設定します。 |
| FULL | FULL([qb_name] TBL_NAME) | テーブルアクセスパスをメインテーブルと同等に設定します。これは INDEX(TBL_NAME PRIMARY) に相当します。 |
| USE_PLAN_CACHE | USE_PLAN_CACHE(NONE[DEFAULT]) | プランキャッシュの使用を設定します:
|
| USE_MERGE | USE_MERGE([qb_name] TBL_NAME_LIST) | 右テーブルとして指定されたテーブルでMerge Joinを使用するように設定します。 |
| USE_HASH | USE_HASH([qb_name] TBL_NAME_LIST) | 右テーブルとして指定されたテーブルでHash Joinを使用するように設定します。 |
| NO_USE_HASH | NO_USE_HASH([qb_name] TBL_NAME_LIST) | 右テーブルとして指定されたテーブルでHash Joinを使用しないように設定します。 |
| USE_NL | USE_NL([qb_name] TBL_NAME_LIST) | 右テーブルとして指定されたテーブルでNested Loop Joinを使用するように設定します。 |
| USE_BNL | USE_BNL([qb_name] TBL_NAME_LIST) | 右テーブルとして使用する指定テーブルでBlock Nested Loop Joinを使用するように設定します |
| USE_HASH_AGGREGATION | USE_HASH_AGGREGATION([qb_name]) | 集計アルゴリズムをHashに設定します。例:Hash Group ByまたはHash Distinct。 |
| NO_USE_HASH_AGGREGATION | NO_USE_HASH_AGGREGATION([qb_name]) | AggregateメソッドでHash Aggregateを使用せず、Merge Group ByまたはMerge Distinctを使用するように設定します。 |
| USE_LATE_MATERIALIZATION | USE_LATE_MATERIALIZATION | 遅延マテリアライゼーションを使用するように設定します。 |
| NO_USE_LATE_MATERIALIZATION | NO_USE_LATE_MATERIALIZATION | 遅延マテリアライゼーションを使用しないように設定します。 |
| TRACE_LOG | TRACE_LOG | Traceレコードの収集をSHOW TRACE表示用に設定します。 |
| QB_NAME | QB_NAME( NAME ) | Query Blockの名前を設定します。 |
| PARALLEL | PARALLEL(INTNUM) | 分散実行の並列度を設定します。 |
| TOPK | TOPK(PRECISION MINIMUM_ROWS) | あいまいクエリの精度と最小行数を設定します。ここでPRECSIONは整数型で、値の範囲は[0,100]です。これはあいまいクエリの行数の割合を表します。MINIMUM_ROWSは返される最小行数です。 |
| MAX_CONCURRENT | MAX_CONCURRENT(n) | このSQLテキストの並列数を制限します。 |
UNION_MERGE
注意OceanBaseデータベースはV4.4.1バージョンから |
UNION_MERGE(table_name index_name_list) | 対応するIndex Merge計画を設定します。 |
| PUSH_SUBQ | PUSH_SUBQ[(@qb_name)] | 最適化エンジンに対し、結合に書き換えられていないサブクエリを早期に実行するよう指示します。 |
| NO PUSH_SUBQ | NO PUSH_SUBQ[(@qb_name)] | PUSH_SUBQの逆操作で、オプティマイザーが結合されていないサブクエリを最後に実行するように最適化します。 |
| OPT_PARAM | OPT_PARAM(parameter_name [,] parameter_value) | クエリレベルで一部のオプティマイザー関連のパラメーター/システム変数を更新するために指定します。 |
| INDEX_MERGE | INDEX_MERGE([@query_block_name] tbl_name [index_name [,index_name]...]) | 指定されたテーブルがインデックスマージ計画を使用するかどうかを制御します。
注意
|
| NO_INDEX_MERGE | NO_INDEX_MERGE([@query_block_name] tbl_name [index_name [,index_name]...]) | 指定されたテーブルが指定されたインデックスを使用してインデックスマージ計画を生成しないように制御します。
注意
|
説明
QB_NAMEの構文は次のとおりです:@NAMETBL_NAMEの構文は次のとおりです:[db_name.]relation_name [qb_name]
QB_NAMEパラメータ
DMLステートメントでは、各query_blockにはユーザーが指定するかシステムが自動生成するQB_NAME(Query Block Name)が付けられます。ユーザーがHintでQB_NAMEを指定しない場合、システムはSEL$1、SEL$2、UPD$1、DEL$1の順に、左から右へと(実際にはResolverの解析順序でもある)順次生成します。
QB_NAMEにより、各テーブルを正確に特定したり、任意のQuery Blockの動作を指定したりできます。TBL_NAME内のQB_NAMEはテーブルの位置付けに使用され、Hintの最初のQB_NAMEはそのHintがどのquery_blockに作用するかを特定するために使用されます。
以下の例のように、デフォルトルールでは、SEL$1のt1テーブルにt1_c1パスが選択され、SEL$2のt2テーブルにはプライマリテーブル(Primary)アクセスが選択されます。
obclient> CREATE TABLE t1(c1 INT, c2 INT, KEY t1_c1(c1));
Query OK, 0 rows affected
obclient> CREATE TABLE t2(c1 INT, c2 INT, KEY t2_c1(c1));
Query OK, 0 rows affected
obclient> EXPLAIN SELECT * FROM t1, (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5)
WHERE t1.c1 = 1;
+-----------------------------------------------------------------------------------------------------------+
| Query Plan |
+-----------------------------------------------------------------------------------------------------------+
| ====================================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| ---------------------------------------------------------------------- |
| |0 |NESTED-LOOP JOIN CARTESIAN | |1 |7 | |
| |1 |├─TABLE RANGE SCAN |t1(t1_c1) |1 |7 | |
| |2 |└─MATERIAL | |1 |3 | |
| |3 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|1 |3 | |
| |4 | └─TABLE FULL SCAN |t2 |1 |3 | |
| ====================================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t1.c1], [t1.c2], [ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16 |
| conds(nil), nl_params_(nil), use_batch=false |
| 1 - output([t1.c1], [t1.c2]), filter(nil), rowset=16 |
| access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0) |
| is_index_back=true, is_global_index=false, |
| range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX), |
| range_cond([t1.c1 = 1]) |
| 2 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16 |
| 3 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16 |
| access([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]) |
| 4 - output([t2.c1], [t2.c2]), filter([t2.c2 = 1]), rowset=16 |
| access([t2.c2], [t2.c1]), partitions(p0) |
| limit(5), offset(nil), is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([t2.__pk_increment]), range(MIN ; MAX)always true |
+-----------------------------------------------------------------------------------------------------------+
25 rows in set
SQLがHintを通じてSEL$1のt1テーブルにプライマリテーブルを、SEL$2のt2テーブルにインデックスを指定する場合、例は以下のとおりです:
obclient> EXPLAIN SELECT /*+INDEX(t1 PRIMARY) INDEX(@SEL$2 t2 t2_c1)*/ *
FROM t1 , (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5)
WHERE t1.c1 = 1;
+----------------------------------------------------------------------------------------------------------+
| Query Plan |
+----------------------------------------------------------------------------------------------------------+
| ====================================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| ---------------------------------------------------------------------- |
| |0 |NESTED-LOOP JOIN CARTESIAN | |1 |3 | |
| |1 |├─TABLE FULL SCAN |t1 |1 |3 | |
| |2 |└─MATERIAL | |1 |7 | |
| |3 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|1 |7 | |
| |4 | └─TABLE FULL SCAN |t2(t2_c1) |1 |7 | |
| ====================================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t1.c1], [t1.c2], [ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16 |
| conds(nil), nl_params_(nil), use_batch=false |
| 1 - output([t1.c1], [t1.c2]), filter([t1.c1 = 1]), rowset=16 |
| access([t1.c1], [t1.c2]), partitions(p0) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([t1.__pk_increment]), range(MIN ; MAX)always true |
| 2 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16 |
| 3 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16 |
| access([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]) |
| 4 - output([t2.c1], [t2.c2]), filter([t2.c2 = 1]), rowset=16 |
| access([t2.__pk_increment], [t2.c2], [t2.c1]), partitions(p0) |
| limit(5), offset(nil), is_index_back=true, is_global_index=false, filter_before_indexback[false], |
| range_key([t2.c1], [t2.__pk_increment]), range(MIN,MIN ; MAX,MAX)always true |
+----------------------------------------------------------------------------------------------------------+
24 rows in set
説明
INDEX(t1 PRIMARY)はもともとSEL$1に存在しているため、Hintが作用するQuery Blockを再度指定する必要はありません。
上記の例では、SQLは以下のようにも書けます:
SELECT /*+INDEX(t1 PRIMARY) INDEX(@SEL$2 t2@SEL$2 t2_c1)*/ * FROM t1 , (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5) WHERE t1.c1 = 1;
または:
SELECT /*+INDEX(t1 PRIMARY)*/ * FROM t1 , (SELECT /*+INDEX(t2 t2_c1)*/ * FROM t2 WHERE c2 = 1 LIMIT 5) WHERE t1.c1 = 1;
または:
SELECT /*+INDEX(@SEL$1 t1 PRIMARY) INDEX(@SEL$2 t2 t2_c1)*/ * FROM t1 , (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5) WHERE t1.c1 = 1;
このHintに関するすべての情報は、EXPLAIN EXTENDEDコマンドの実行結果にあるOutline Dataで確認できます。
obclient> EXPLAIN EXTENDED SELECT * FROM t1, (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5)
WHERE t1.c1 = 1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ====================================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| ---------------------------------------------------------------------- |
| |0 |NESTED-LOOP JOIN CARTESIAN | |1 |7 | |
| |1 |├─TABLE RANGE SCAN |t1(t1_c1) |1 |7 | |
| |2 |└─MATERIAL | |1 |3 | |
| |3 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|1 |3 | |
| |4 | └─TABLE FULL SCAN |t2 |1 |3 | |
| ====================================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t1.c1(0x7f20d7035330)], [t1.c2(0x7f20d70358b0)], [ANONYMOUS_VIEW1.c1(0x7f20d7035be0)], [ANONYMOUS_VIEW1.c2(0x7f20d7035f10)]), filter(nil), rowset=16 |
| conds(nil), nl_params_(nil), use_batch=false |
| 1 - output([t1.c1(0x7f20d7035330)], [t1.c2(0x7f20d70358b0)]), filter(nil), rowset=16 |
| access([t1.__pk_increment(0x7f20d7036b10)], [t1.c1(0x7f20d7035330)], [t1.c2(0x7f20d70358b0)]), partitions(p0) |
| is_index_back=true, is_global_index=false, |
| range_key([t1.c1(0x7f20d7035330)], [t1.__pk_increment(0x7f20d7036b10)]), range(1,MIN ; 1,MAX), |
| range_cond([t1.c1(0x7f20d7035330) = 1(0x7f20d7034b70)]) |
| 2 - output([ANONYMOUS_VIEW1.c1(0x7f20d7035be0)], [ANONYMOUS_VIEW1.c2(0x7f20d7035f10)]), filter(nil), rowset=16 |
| 3 - output([ANONYMOUS_VIEW1.c1(0x7f20d7035be0)], [ANONYMOUS_VIEW1.c2(0x7f20d7035f10)]), filter(nil), rowset=16 |
| access([ANONYMOUS_VIEW1.c1(0x7f20d7035be0)], [ANONYMOUS_VIEW1.c2(0x7f20d7035f10)]) |
| 4 - output([t2.c1(0x7f20d7033a10)], [t2.c2(0x7f20d7033490)]), filter([t2.c2(0x7f20d7033490) = 1(0x7f20d7032cd0)]), rowset=16 |
| access([t2.c2(0x7f20d7033490)], [t2.c1(0x7f20d7033a10)]), partitions(p0) |
| limit(5), offset(nil), is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([t2.__pk_increment(0x7f20d70365e0)]), range(MIN ; MAX)always true |
| Used Hint: |
| ------------------------------------- |
| /*+ |
| |
| */ |
| Qb name trace: |
| ------------------------------------- |
| stmt_id:0, stmt_type:T_EXPLAIN |
| stmt_id:1, SEL$1 |
| stmt_id:2, SEL$2 |
| Outline Data: |
| ------------------------------------- |
| /*+ |
| BEGIN_OUTLINE_DATA |
| LEADING(@"SEL$1" ("aabb"."t1"@"SEL$1" "ANONYMOUS_VIEW1"@"SEL$1")) |
| USE_NL(@"SEL$1" "ANONYMOUS_VIEW1"@"SEL$1") |
| USE_NL_MATERIALIZATION(@"SEL$1" "ANONYMOUS_VIEW1"@"SEL$1") |
| INDEX(@"SEL$1" "aabb"."t1"@"SEL$1" "t1_c1") |
| FULL(@"SEL$2" "aabb"."t2"@"SEL$2") |
| OPTIMIZER_FEATURES_ENABLE('4.3.0.0') |
| END_OUTLINE_DATA |
| */ |
| Optimization Info: |
| ------------------------------------- |
| t1: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:1 |
| output_rows:1 |
| table_dop:1 |
| dop_method:Table DOP |
| avaiable_index_name:[t1_c1, t1] |
| unstable_index_name:[t1] |
| stats version:0 |
| dynamic sampling level:0 |
| estimation method:[DEFAULT, STORAGE] |
| t2: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:1 |
| table_dop:1 |
| dop_method:Table DOP |
| avaiable_index_name:[t2_c1, t2] |
| pruned_index_name:[t2_c1] |
| stats version:0 |
| dynamic sampling level:0 |
| estimation method:[DEFAULT, STORAGE] |
| Plan Type: |
| LOCAL |
| Note: |
| Degree of Parallelisim is 1 because of table property |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
79 rows in set
Hintの使用ルール
Hintの一般的な使用ルールは以下のとおりです:
Query Blockを指定していないHintは、現在のQuery Blockに対して作用します。
例1:
t2テーブルはQuery Block2にあり、リライトによってQuery Block1に昇格させることができないため、Hintは効果を発揮しません。obclient> EXPLAIN SELECT /*+INDEX(t2 t2_c1)*/ * FROM t1 , (SELECT * FROM t2 WHERE c2 = 1 LIMIT 5) WHERE t1.c1 = 1; +-----------------------------------------------------------------------------------------------------------+ | Query Plan | +-----------------------------------------------------------------------------------------------------------+ | ====================================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ---------------------------------------------------------------------- | | |0 |NESTED-LOOP JOIN CARTESIAN | |1 |7 | | | |1 |├─TABLE RANGE SCAN |t1(t1_c1) |1 |7 | | | |2 |└─MATERIAL | |1 |3 | | | |3 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|1 |3 | | | |4 | └─TABLE FULL SCAN |t2 |1 |3 | | | ====================================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output([t1.c1], [t1.c2], [ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16 | | conds(nil), nl_params_(nil), use_batch=false | | 1 - output([t1.c1], [t1.c2]), filter(nil), rowset=16 | | access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0) | | is_index_back=true, is_global_index=false, | | range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX), | | range_cond([t1.c1 = 1]) | | 2 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16 | | 3 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]) | | 4 - output([t2.c1], [t2.c2]), filter([t2.c2 = 1]), rowset=16 | | access([t2.c2], [t2.c1]), partitions(p0) | | limit(5), offset(nil), is_index_back=false, is_global_index=false, filter_before_indexback[false], | | range_key([t2.__pk_increment]), range(MIN ; MAX)always true | +-----------------------------------------------------------------------------------------------------------+ 25 rows in set例2:オプティマイザーがサブクエリと外部クエリを再統合し、単一のQuery Blockのみを使用できる場合、Hintは有効になる可能性があります。
obclient> EXPLAIN SELECT /*+INDEX(t2 t2_c1)*/ * FROM t1 , (SELECT * FROM t2 WHERE c2 = 1) WHERE t1.c1 = 1; +------------------------------------------------------------------------------------+ | Query Plan | +------------------------------------------------------------------------------------+ | ================================================================ | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ---------------------------------------------------------------- | | |0 |NESTED-LOOP JOIN CARTESIAN | |1 |7 | | | |1 |├─TABLE RANGE SCAN |t1(t1_c1)|1 |7 | | | |2 |└─MATERIAL | |1 |7 | | | |3 | └─TABLE FULL SCAN |t2(t2_c1)|1 |7 | | | ================================================================ | | Outputs & filters: | | ------------------------------------- | | 0 - output([t1.c1], [t1.c2], [t2.c1], [t2.c2]), filter(nil), rowset=16 | | conds(nil), nl_params_(nil), use_batch=false | | 1 - output([t1.c1], [t1.c2]), filter(nil), rowset=16 | | access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0) | | is_index_back=true, is_global_index=false, | | range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX), | | range_cond([t1.c1 = 1]) | | 2 - output([t2.c1], [t2.c2]), filter(nil), rowset=16 | | 3 - output([t2.c2], [t2.c1]), filter([t2.c2 = 1]), rowset=16 | | access([t2.__pk_increment], [t2.c2], [t2.c1]), partitions(p0) | | is_index_back=true, is_global_index=false, filter_before_indexback[false], | | range_key([t2.c1], [t2.__pk_increment]), range(MIN,MIN ; MAX,MAX)always true | +------------------------------------------------------------------------------------+ 22 rows in set
上記の例では、オプティマイザーが何らかの理由(例えば、サブクエリ内部の操作が昇格・メジャーコンパクションを妨げている場合)でサブクエリ(SELECT * FROM t2 WHERE c2 = 1)を外部クエリに統合できない場合、t2テーブルは依然としてサブクエリの一部と見なされるため、外部クエリ内のHintは無効になります。
以下の例では、外部クエリとサブクエリがどちらも同じt1テーブルを参照し、どちらもPRIMARYインデックスを利用しようとするため、オプティマイザーがHintの解釈と処理において競合に直面し、Hintが無効になる可能性があります。
obclient> EXPLAIN SELECT /*+INDEX(t1 PRIMARY)*/ *
FROM t1 , (SELECT * FROM t1 WHERE c1 = 1)
WHERE t1.c1 = 1;
+--------------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------------+
| ================================================================ |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| ---------------------------------------------------------------- |
| |0 |NESTED-LOOP JOIN CARTESIAN | |1 |7 | |
| |1 |├─TABLE RANGE SCAN |t1(t1_c1)|1 |7 | |
| |2 |└─MATERIAL | |1 |7 | |
| |3 | └─TABLE RANGE SCAN |t1(t1_c1)|1 |7 | |
| ================================================================ |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t1.c1], [t1.c2], [t1.c1], [t1.c2]), filter(nil), rowset=16 |
| conds(nil), nl_params_(nil), use_batch=false |
| 1 - output([t1.c1], [t1.c2]), filter(nil), rowset=16 |
| access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0) |
| is_index_back=true, is_global_index=false, |
| range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX), |
| range_cond([t1.c1 = 1]) |
| 2 - output([t1.c1], [t1.c2]), filter(nil), rowset=16 |
| 3 - output([t1.c1], [t1.c2]), filter(nil), rowset=16 |
| access([t1.__pk_increment], [t1.c1], [t1.c2]), partitions(p0) |
| is_index_back=true, is_global_index=false, |
| range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX), |
| range_cond([t1.c1 = 1]) |
+--------------------------------------------------------------------------+
23 rows in set
接続方法に関するHintで指定されたテーブルが見つからない場合、そのテーブルは無視され、他の指定は引き続き有効です。オプティマイザーが指定された接続方法を生成できない場合、他の方法を選択し、Hintは無効になります。
接続順序に関するHintで指定されたテーブルに見つからないものがある場合、そのHintは完全に無効になります。
よく使われるヒントと構文
他のデータベースの動作と比較して、OceanBaseデータベースのオプティマイザーは動的計画法に基づいており、考えられるすべての最適パスを事前に検討済みです。ヒントの主な役割は、オプティマイザーの動作を指定し、その指示に従ってSQLクエリを実行することです。
INDEX ヒント
INDEX ヒントの構文は、MySQLモードとOracleモードの両方をサポートしています。
INDEXヒントのOracle構文は以下のとおりです:
SELECT/*+INDEX(table_name index_name) */ * FROM table_name;
INDEXヒントのMySQL構文は以下のとおりです:
table_name [[AS] alias] [index_hint_list]
index_hint_list:
index_hint [, index_hint] ...
index_hint:
USE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
| IGNORE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
| FORCE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
index_list:
index_name [, index_name] ...
Oracleモードの構文では、テーブルごとに1つの INDEX のみを指定できますが、MySQLモードの構文では複数指定が可能です。ただし、OceanBaseデータベースのMySQLモード構文でも複数の INDEX を指定できますが、USE および FORCE 方式では、最初の INDEX が使用されて PATH が生成されます。SQL文にその INDEX の filter がなく、結果として全スキャンで同時にテーブルに戻る場合でもです(これは、OceanBaseデータベースの現在の設計では、ヒントを書いた人間の方がプログラムよりもそのパスの方が優れていると判断しているためです)。IGNORE 方式は、指定されたすべての INDEX を無視します。USE、FORCE 方式とOracleのヒント方式は実質的に同じであり、その方式の INDEX が存在しないか invalid 状態にある場合、ヒントは無効になります。IGNORE 方式については、主表を含むすべての INDEX を無視した場合、ヒントは無効になります。
SQL文において、テーブル名にエイリアス(table_name [AS] alias)が存在する場合、INDEX を有効にするにはテーブルエイリアスを記述する必要があります。例:
obclient> create table t1(c1 int, c2 int, c3 int);
Query OK, 0 rows affected
obclient> create index idx1 on t1(c1);
Query OK, 0 rows affected
obclient> create index idx2 on t1(c2);
Query OK, 0 rows affected
obclient> insert into t1 with recursive cte(n) as (select 1 from dual union all select n+1 from cte where n < 1000) select n, mod(n, 3), n from cte;
Query OK, 1 row affected
obclient> analyze table t1 COMPUTE STATISTICS for all columns size 128;
Query OK, 0 rows affected
obclient> explain select * from t1 where c1 = 1 and c2 = 1;
+-----------------------------------------------------------------------------------+
| Query Plan |
+-----------------------------------------------------------------------------------+
| ==================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| ---------------------------------------------------- |
| |0 |TABLE RANGE SCAN|t1(idx1)|1 |7 | |
| ==================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c2 = 1]), rowset=16 |
| access([t1.__pk_increment], [t1.c1], [t1.c2], [t1.c3]), partitions(p0) |
| is_index_back=true, is_global_index=false, filter_before_indexback[false], |
| range_key([t1.c1], [t1.__pk_increment]), range(1,MIN ; 1,MAX), |
| range_cond([t1.c1 = 1]) |
+-----------------------------------------------------------------------------------+
12 rows in set
-------有効な index
obclient> explain select /*+index(t idx2)*/ * from t1 t where c1 = 1 and c2 = 1;
+-----------------------------------------------------------------------------------+
| Query Plan |
+-----------------------------------------------------------------------------------+
| =================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| --------------------------------------------------- |
| |0 |TABLE RANGE SCAN|t(idx2)|1 |812 | |
| =================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t.c1], [t.c2], [t.c3]), filter([t.c1 = 1]), rowset=16 |
| access([t.__pk_increment], [t.c1], [t.c2], [t.c3]), partitions(p0) |
| is_index_back=true, is_global_index=false, filter_before_indexback[false], |
| range_key([t.c2], [t.__pk_increment]), range(1,MIN ; 1,MAX), |
| range_cond([t.c2 = 1]) |
+-----------------------------------------------------------------------------------+
12 rows in set
-------無効な index
obclient> explain select /*+index(t1 idx2)*/ * from t1 t where c1 = 1 and c2 = 1;
+-----------------------------------------------------------------------------------+
| Query Plan |
+-----------------------------------------------------------------------------------+
| =================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| --------------------------------------------------- |
| |0 |TABLE RANGE SCAN|t(idx1)|1 |7 | |
| =================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t.c1], [t.c2], [t.c3]), filter([t.c2 = 1]), rowset=16 |
| access([t.__pk_increment], [t.c1], [t.c2], [t.c3]), partitions(p0) |
| is_index_back=true, is_global_index=false, filter_before_indexback[false], |
| range_key([t.c1], [t.__pk_increment]), range(1,MIN ; 1,MAX), |
| range_cond([t.c1 = 1]) |
+-----------------------------------------------------------------------------------+
12 rows in set
例の結果から、c1 = 1 のフィルタリングは c2 = 1 よりも優先されるため、INDEX ヒントが無効な場合、オプティマイザーのインデックス選択メカニズムが IDX1 を使用しています。
FULLヒント
FULL ヒントの構文は、テーブルに対してメインテーブルスキャンを指定するために使用され、構文は次のとおりです:
/*+ FULL(table_name)*/
FULL ヒントは、指定したテーブルに対してメインテーブルスキャンを選択するために使用され、INDEX ヒント /*+ INDEX(table_name PRIMARY)*/ と同等です。
ORDEREDヒント
ORDERED ヒントは、FROM 句の後に続くテーブルの順序で結合順序を指定することができます。構文は次のとおりです:
/*+ ORDERED */
このヒントを指定した後にSQLがリライトされる場合、リライト後の stmt のFrom Itemsの順序で結合されます。これは、リライト時に sub_query がFrom Itemsの対応する位置に新しいTable Itemを挿入するためです。
LEADINGヒント
LEADING ヒントは、テーブルの結合順序を指定できます。構文は次のとおりです:
/*+ LEADING(table_name_list)*/
table_name_list 内では () を使用して内部の各テーブルの結合優先順位を指定し、複雑な結合を定義できます。例:
obclient> EXPLAIN BASIC SELECT /*+LEADING(d c b a)*/ * FROM t1 a, t1 b, t1 c, t1 d;
+---------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+---------------------------------------------------------------------------------------------------------------------------------------+
| ========================================= |
| |ID|OPERATOR |NAME| |
| ----------------------------------------- |
| |0 |NESTED-LOOP JOIN CARTESIAN | | |
| |1 |├─NESTED-LOOP JOIN CARTESIAN | | |
| |2 |│ ├─NESTED-LOOP JOIN CARTESIAN | | |
| |3 |│ │ ├─TABLE FULL SCAN |d | |
| |4 |│ │ └─MATERIAL | | |
| |5 |│ │ └─TABLE FULL SCAN |c | |
| |6 |│ └─MATERIAL | | |
| |7 |│ └─TABLE FULL SCAN |b | |
| |8 |└─MATERIAL | | |
| |9 | └─TABLE FULL SCAN |a | |
| ========================================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 1 - output([b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 2 - output([c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 3 - output([d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| access([d.c1], [d.c2], [d.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([d.__pk_increment]), range(MIN ; MAX)always true |
| 4 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256 |
| 5 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256 |
| access([c.c1], [c.c2], [c.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([c.__pk_increment]), range(MIN ; MAX)always true |
| 6 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256 |
| 7 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256 |
| access([b.c1], [b.c2], [b.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([b.__pk_increment]), range(MIN ; MAX)always true |
| 8 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256 |
| 9 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256 |
| access([a.c1], [a.c2], [a.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([a.__pk_increment]), range(MIN ; MAX)always true |
+---------------------------------------------------------------------------------------------------------------------------------------+
41 rows in set
obclient> EXPLAIN BASIC SELECT /*+LEADING((d c) (b a))*/ * FROM t1 a, t1 b, t1 c, t1 d;
+---------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+---------------------------------------------------------------------------------------------------------------------------------------+
| ========================================= |
| |ID|OPERATOR |NAME| |
| ----------------------------------------- |
| |0 |NESTED-LOOP JOIN CARTESIAN | | |
| |1 |├─NESTED-LOOP JOIN CARTESIAN | | |
| |2 |│ ├─TABLE FULL SCAN |d | |
| |3 |│ └─MATERIAL | | |
| |4 |│ └─TABLE FULL SCAN |c | |
| |5 |└─MATERIAL | | |
| |6 | └─NESTED-LOOP JOIN CARTESIAN | | |
| |7 | ├─TABLE FULL SCAN |b | |
| |8 | └─MATERIAL | | |
| |9 | └─TABLE FULL SCAN |a | |
| ========================================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 1 - output([c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 2 - output([d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| access([d.c1], [d.c2], [d.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([d.__pk_increment]), range(MIN ; MAX)always true |
| 3 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256 |
| 4 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256 |
| access([c.c1], [c.c2], [c.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([c.__pk_increment]), range(MIN ; MAX)always true |
| 5 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3]), filter(nil), rowset=256 |
| 6 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 7 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256 |
| access([b.c1], [b.c2], [b.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([b.__pk_increment]), range(MIN ; MAX)always true |
| 8 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256 |
| 9 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256 |
| access([a.c1], [a.c2], [a.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([a.__pk_increment]), range(MIN ; MAX)always true |
+---------------------------------------------------------------------------------------------------------------------------------------+
41 rows in set
obclient> EXPLAIN BASIC SELECT /*+LEADING((d c b) a))*/ * FROM t1 a, t1 b, t1 c, t1 d;
+---------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+---------------------------------------------------------------------------------------------------------------------------------------+
| ========================================= |
| |ID|OPERATOR |NAME| |
| ----------------------------------------- |
| |0 |NESTED-LOOP JOIN CARTESIAN | | |
| |1 |├─NESTED-LOOP JOIN CARTESIAN | | |
| |2 |│ ├─NESTED-LOOP JOIN CARTESIAN | | |
| |3 |│ │ ├─TABLE FULL SCAN |d | |
| |4 |│ │ └─MATERIAL | | |
| |5 |│ │ └─TABLE FULL SCAN |c | |
| |6 |│ └─MATERIAL | | |
| |7 |│ └─TABLE FULL SCAN |b | |
| |8 |└─MATERIAL | | |
| |9 | └─TABLE FULL SCAN |a | |
| ========================================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([a.c1], [a.c2], [a.c3], [b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 1 - output([b.c1], [b.c2], [b.c3], [c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 2 - output([c.c1], [c.c2], [c.c3], [d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 3 - output([d.c1], [d.c2], [d.c3]), filter(nil), rowset=256 |
| access([d.c1], [d.c2], [d.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([d.__pk_increment]), range(MIN ; MAX)always true |
| 4 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256 |
| 5 - output([c.c1], [c.c2], [c.c3]), filter(nil), rowset=256 |
| access([c.c1], [c.c2], [c.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([c.__pk_increment]), range(MIN ; MAX)always true |
| 6 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256 |
| 7 - output([b.c1], [b.c2], [b.c3]), filter(nil), rowset=256 |
| access([b.c1], [b.c2], [b.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([b.__pk_increment]), range(MIN ; MAX)always true |
| 8 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256 |
| 9 - output([a.c1], [a.c2], [a.c3]), filter(nil), rowset=256 |
| access([a.c1], [a.c2], [a.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([a.__pk_increment]), range(MIN ; MAX)always true |
+---------------------------------------------------------------------------------------------------------------------------------------+
41 rows in set
ユーザーが指定した順序で結合が実行されるようにするために、LEADING ヒントのチェックは厳密です。ヒントで指定された table_name が存在しない場合、またはヒント内に重複するテーブルがある場合、LEADING ヒントは無効になります。オプティマイザーの結合処理中に、table_id に対応するテーブルがFrom Itemsで見つからない場合、リライトが発生する可能性があります。その場合、当該テーブル以降に指定された JOIN 順序は無効になりますが、そのテーブルより前に指定された JOIN 順序は引き続き有効です。
USE_MERGE ヒント
USE_MERGE は、結合時にテーブルがマージ結合アルゴリズムを使用するよう指定し、指定されたテーブルを右テーブルとします。構文は以下のとおりです:
/*+ USE_MERGE(table_name_list) */
注意
OceanBaseデータベースでは、マージ結合には等価条件の join-condition が必要であるため、等価条件のない2つのテーブルを結合する場合、use_merge は無効になります。
マージ結合アルゴリズムにおいて、A Merge Join B と B Merge Join A が等価であるかどうかについては、現在最終的な結論は出ていません。コストモデルによれば、マージ結合は計算コストを算出する際に左右のテーブルを区別しており、これによりヒントの柔軟性も高まっています。そのため、現在のマージ結合では左右のテーブルが区別されており、use_merge ヒントはテーブルが右テーブルとして使用される場合にのみ有効になります。
USE_NLヒント
JOINに関連するヒントの基本構造は以下のとおりです: join_hint_name ( @ qb_name table_name_list) 基本的な意味合いは、結合の右テーブルがtable_name_listにマッチする場合、ヒントの意味に従って実行計画を生成することです。通常はLEADINGヒントを使用して結合順序を指定し、table_name_list内のテーブルを右テーブルとします。そうでない場合、ヒントは結合順序の変更によって無効になります。
ここで、table_name_listには以下の形式が可能です:
- 単一テーブル use_nl ( t1 ):t1を右テーブルとする場合にNested Loop Joinを使用します。
- 複数の単一テーブル use_nl ( t1 t2 ... ):t1またはt2などを右テーブルとする場合にNested Loop Joinを使用します。
- 複数のテーブル use_nl ( (t1 t2) ):t1 join t2を右テーブルとする場合にNested Loop Joinを使用します。t1/t2の結合順序や方法は無視されます。
- 複数のテーブルグループ use_nl ( t1 (t2 t3) (t4 t5 t6) ... ):t1 / t2 join t3 / t4 join t5 join t6などのテーブルを右テーブルとする場合にNested Loop Joinを使用します。
USE_NLは、テーブルを右テーブルとして指定し、結合時にNested Loop Joinアルゴリズムを使用するようにします。構文は以下のとおりです:
/*+ USE_NL(table_name_list) */
例:
obclient> CREATE TABLE t0(c1 INT, c2 INT, c3 INT);
obclient> CREATE TABLE t1(c1 INT, c2 INT, c3 INT);
obclient> CREATE TABLE t2(c1 INT, c2 INT, c3 INT);
obclient> EXPLAIN EXTENDED SELECT /*+LEADING(t0 t1) USE_NL(t1)*/ *
FROM t0, t1 WHERE t0.c1 = t1.c1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| =================================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| --------------------------------------------------- |
| |0 |NESTED-LOOP JOIN | |1 |3 | |
| |1 |├─TABLE FULL SCAN |t0 |1 |3 | |
| |2 |└─MATERIAL | |1 |3 | |
| |3 | └─TABLE FULL SCAN|t1 |1 |3 | |
| =================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t0.c1(0x7f218dc21640)], [t0.c2(0x7f218dc21f00)], [t0.c3(0x7f218dc22230)], [t1.c1(0x7f218dc21980)], [t1.c2(0x7f218dc22560)], [t1.c3(0x7f218dc22890)]), filter(nil), rowset=16 |
| conds([t0.c1(0x7f218dc21640) = t1.c1(0x7f218dc21980)(0x7f218dc20e80)]), nl_params_(nil), use_batch=false |
| 1 - output([t0.c1(0x7f218dc21640)], [t0.c2(0x7f218dc21f00)], [t0.c3(0x7f218dc22230)]), filter(nil), rowset=16 |
| access([t0.c1(0x7f218dc21640)], [t0.c2(0x7f218dc21f00)], [t0.c3(0x7f218dc22230)]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t0.__pk_increment(0x7f218dc230f0)]), range(MIN ; MAX)always true |
| 2 - output([t1.c1(0x7f218dc21980)], [t1.c2(0x7f218dc22560)], [t1.c3(0x7f218dc22890)]), filter(nil), rowset=16 |
| 3 - output([t1.c1(0x7f218dc21980)], [t1.c2(0x7f218dc22560)], [t1.c3(0x7f218dc22890)]), filter(nil), rowset=16 |
| access([t1.c1(0x7f218dc21980)], [t1.c2(0x7f218dc22560)], [t1.c3(0x7f218dc22890)]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t1.__pk_increment(0x7f218dc23420)]), range(MIN ; MAX)always true |
| Used Hint: |
| ------------------------------------- |
| /*+ |
| |
| LEADING(("t0" "t1")) |
| USE_NL("t1") |
| */ |
| Qb name trace: |
| ------------------------------------- |
| stmt_id:0, stmt_type:T_EXPLAIN |
| stmt_id:1, SEL$1 |
| Outline Data: |
| ------------------------------------- |
| /*+ |
| BEGIN_OUTLINE_DATA |
| LEADING(@"SEL$1" ("cccc"."t0"@"SEL$1" "cccc"."t1"@"SEL$1")) |
| USE_NL(@"SEL$1" "cccc"."t1"@"SEL$1") |
| USE_NL_MATERIALIZATION(@"SEL$1" "cccc"."t1"@"SEL$1") |
| FULL(@"SEL$1" "cccc"."t0"@"SEL$1") |
| FULL(@"SEL$1" "cccc"."t1"@"SEL$1") |
| OPTIMIZER_FEATURES_ENABLE('4.3.0.0') |
| END_OUTLINE_DATA |
| */ |
| Optimization Info: |
| ------------------------------------- |
| t0: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:1 |
| table_dop:1 |
| dop_method:Table DOP |
| avaiable_index_name:[t0] |
| stats version:0 |
| dynamic sampling level:1 |
| estimation method:[DYNAMIC SAMPLING FULL] |
| t1: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:1 |
| table_dop:1 |
| dop_method:Table DOP |
| avaiable_index_name:[t1] |
| stats version:0 |
| dynamic sampling level:1 |
| estimation method:[DYNAMIC SAMPLING FULL] |
| Plan Type: |
| LOCAL |
| Note: |
| Degree of Parallelisim is 1 because of table property |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
74 rows in set
obclient> EXPLAIN EXTENDED SELECT /*+LEADING(t0 (t1 t2)) USE_NL((t1 t2))*/ *
FROM t0, t1, t2 WHERE t0.c1 = t1.c1 AND t0.c1 = t2.c1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ===================================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| ----------------------------------------------------- |
| |0 |NESTED-LOOP JOIN | |1 |3 | |
| |1 |├─TABLE FULL SCAN |t0 |1 |3 | |
| |2 |└─MATERIAL | |1 |5 | |
| |3 | └─HASH JOIN | |1 |5 | |
| |4 | ├─TABLE FULL SCAN|t1 |1 |3 | |
| |5 | └─TABLE FULL SCAN|t2 |1 |3 | |
| ===================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t0.c1(0x7f217d422a30)], [t0.c2(0x7f217d424700)], [t0.c3(0x7f217d424a30)], [t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)], |
| [t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), filter(nil), rowset=16 |
| conds([t0.c1(0x7f217d422a30) = t1.c1(0x7f217d422d70)(0x7f217d422270)]), nl_params_(nil), use_batch=false |
| 1 - output([t0.c1(0x7f217d422a30)], [t0.c2(0x7f217d424700)], [t0.c3(0x7f217d424a30)]), filter(nil), rowset=16 |
| access([t0.c1(0x7f217d422a30)], [t0.c2(0x7f217d424700)], [t0.c3(0x7f217d424a30)]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t0.__pk_increment(0x7f217d426110)]), range(MIN ; MAX)always true |
| 2 - output([t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)], [t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), filter(nil), rowset=16 |
| 3 - output([t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)], [t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), filter(nil), rowset=16 |
| equal_conds([t1.c1(0x7f217d422d70) = t2.c1(0x7f217d424180)(0x7f217d4c2500)]), other_conds(nil) |
| 4 - output([t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)]), filter(nil), rowset=16 |
| access([t1.c1(0x7f217d422d70)], [t1.c2(0x7f217d424d60)], [t1.c3(0x7f217d425090)]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t1.__pk_increment(0x7f217d426440)]), range(MIN ; MAX)always true |
| 5 - output([t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), filter(nil), rowset=16 |
| access([t2.c1(0x7f217d424180)], [t2.c2(0x7f217d4253c0)], [t2.c3(0x7f217d4256f0)]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t2.__pk_increment(0x7f217d426770)]), range(MIN ; MAX)always true |
| Used Hint: |
| ------------------------------------- |
| /*+ |
| |
| LEADING(("t0" ("t1" "t2"))) |
| USE_NL(("t1" "t2")) |
| */ |
| Qb name trace: |
| ------------------------------------- |
| stmt_id:0, stmt_type:T_EXPLAIN |
| stmt_id:1, SEL$1 |
| Outline Data: |
| ------------------------------------- |
| /*+ |
| BEGIN_OUTLINE_DATA |
| LEADING(@"SEL$1" ("cccc"."t0"@"SEL$1" ("cccc"."t1"@"SEL$1" "cccc"."t2"@"SEL$1"))) |
| USE_NL(@"SEL$1" ("cccc"."t2"@"SEL$1" "cccc"."t1"@"SEL$1")) |
| USE_NL_MATERIALIZATION(@"SEL$1" ("cccc"."t2"@"SEL$1" "cccc"."t1"@"SEL$1")) |
| FULL(@"SEL$1" "cccc"."t0"@"SEL$1") |
| USE_HASH(@"SEL$1" "cccc"."t2"@"SEL$1") |
| FULL(@"SEL$1" "cccc"."t1"@"SEL$1") |
| FULL(@"SEL$1" "cccc"."t2"@"SEL$1") |
| OPTIMIZER_FEATURES_ENABLE('4.3.0.0') |
| END_OUTLINE_DATA |
| */ |
| Optimization Info: |
| ------------------------------------- |
| t0: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:1 |
| table_dop:1 |
| dop_method:Table DOP |
| avaiable_index_name:[t0] |
| stats version:0 |
| dynamic sampling level:1 |
| estimation method:[DYNAMIC SAMPLING FULL] |
| t1: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:1 |
| table_dop:1 |
| dop_method:Table DOP |
| avaiable_index_name:[t1] |
| stats version:0 |
| dynamic sampling level:1 |
| estimation method:[DYNAMIC SAMPLING FULL] |
| t2: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:1 |
| table_dop:1 |
| dop_method:Table DOP |
| avaiable_index_name:[t2] |
| stats version:0 |
| dynamic sampling level:1 |
| estimation method:[DYNAMIC SAMPLING FULL] |
| Plan Type: |
| LOCAL |
| Note: |
| Degree of Parallelisim is 1 because of table property |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
97 rows in set
USE_HASH ヒント
USE_HASH は、テーブルを右テーブルとして指定し、結合時にHash Joinアルゴリズムを使用するよう指示します。構文は次のとおりです:
/*+ USE_HASH(table_name_list) */
例:
obclient> CREATE TABLE t0(c1 INT, c2 INT, c3 INT);
obclient> CREATE TABLE t1(c1 INT, c2 INT, c3 INT);
obclient> EXPLAIN EXTENDED SELECT /*+LEADING(t0 t1) USE_HASH(t1)*/ *
FROM t0, t1 WHERE t0.c1 = t1.c1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ================================================= |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| ------------------------------------------------- |
| |0 |HASH JOIN | |1 |5 | |
| |1 |├─TABLE FULL SCAN|t0 |1 |3 | |
| |2 |└─TABLE FULL SCAN|t1 |1 |3 | |
| ================================================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t0.c1(0x7f21a8421640)], [t0.c2(0x7f21a8421f00)], [t0.c3(0x7f21a8422230)], [t1.c1(0x7f21a8421980)], [t1.c2(0x7f21a8422560)], [t1.c3(0x7f21a8422890)]), filter(nil), rowset=16 |
| equal_conds([t0.c1(0x7f21a8421640) = t1.c1(0x7f21a8421980)(0x7f21a8420e80)]), other_conds(nil) |
| 1 - output([t0.c1(0x7f21a8421640)], [t0.c2(0x7f21a8421f00)], [t0.c3(0x7f21a8422230)]), filter(nil), rowset=16 |
| access([t0.c1(0x7f21a8421640)], [t0.c2(0x7f21a8421f00)], [t0.c3(0x7f21a8422230)]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t0.__pk_increment(0x7f21a84230f0)]), range(MIN ; MAX)always true |
| 2 - output([t1.c1(0x7f21a8421980)], [t1.c2(0x7f21a8422560)], [t1.c3(0x7f21a8422890)]), filter(nil), rowset=16 |
| access([t1.c1(0x7f21a8421980)], [t1.c2(0x7f21a8422560)], [t1.c3(0x7f21a8422890)]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t1.__pk_increment(0x7f21a8423420)]), range(MIN ; MAX)always true |
| Used Hint: |
| ------------------------------------- |
| /*+ |
| |
| LEADING(("t0" "t1")) |
| USE_HASH("t1") |
| */ |
| Qb name trace: |
| ------------------------------------- |
| stmt_id:0, stmt_type:T_EXPLAIN |
| stmt_id:1, SEL$1 |
| Outline Data: |
| ------------------------------------- |
| /*+ |
| BEGIN_OUTLINE_DATA |
| LEADING(@"SEL$1" ("dddd"."t0"@"SEL$1" "dddd"."t1"@"SEL$1")) |
| USE_HASH(@"SEL$1" "dddd"."t1"@"SEL$1") |
| FULL(@"SEL$1" "dddd"."t0"@"SEL$1") |
| FULL(@"SEL$1" "dddd"."t1"@"SEL$1") |
| OPTIMIZER_FEATURES_ENABLE('4.3.0.0') |
| END_OUTLINE_DATA |
| */ |
| Optimization Info: |
| ------------------------------------- |
| t0: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:1 |
| table_dop:1 |
| dop_method:Table DOP |
| avaiable_index_name:[t0] |
| stats version:0 |
| dynamic sampling level:1 |
| estimation method:[DYNAMIC SAMPLING FULL] |
| t1: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:1 |
| table_dop:1 |
| dop_method:Table DOP |
| avaiable_index_name:[t1] |
| stats version:0 |
| dynamic sampling level:1 |
| estimation method:[DYNAMIC SAMPLING FULL] |
| Plan Type: |
| LOCAL |
| Note: |
| Degree of Parallelisim is 1 because of table property |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
71 rows in set
PARALLELヒント
PARALLELはステートメントレベルの並列度を指定します。構文は次のとおりです:
/*+ PARALLEL(n) */
ここで、nは整数で、並列度を表します。
OceanBaseデータベースでは、テーブルレベルのPARALLELヒントもサポートしています。構文は次のとおりです:
/*+ PARALLEL(table_name n) */
グローバルな並列度とテーブルレベルの並列度を同時に指定した場合、テーブルレベルの並列度は有効になりません。例:
obclient> CREATE TABLE tbl1 (col1 INT) PARTITION BY HASH(col1) ;
Query OK, 0 rows affected
obclient> EXPLAIN SELECT /*+ PARALLEL(3) PARALLEL(tbl1 5) */ * FROM tbl1;
+----------------------------------------------------------------------+
| Query Plan |
+----------------------------------------------------------------------+
| ========================================================= |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| --------------------------------------------------------- |
| |0 |PX COORDINATOR | |1 |1 | |
| |1 |└─EXCHANGE OUT DISTR |:EX10000|1 |1 | |
| |2 | └─PX BLOCK ITERATOR| |1 |1 | |
| |3 | └─TABLE FULL SCAN|tbl1 |1 |1 | |
| ========================================================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([INTERNAL_FUNCTION(tbl1.col1)]), filter(nil), rowset=16 |
| 1 - output([INTERNAL_FUNCTION(tbl1.col1)]), filter(nil), rowset=16 |
| dop=5 |
| 2 - output([tbl1.col1]), filter(nil), rowset=16 |
| 3 - output([tbl1.col1]), filter(nil), rowset=16 |
| access([tbl1.col1]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([tbl1.__pk_increment]), range(MIN ; MAX)always true |
+----------------------------------------------------------------------+
18 rows in set
UNION_MERGE ヒント
注意
OceanBaseデータベースはV4.4.1バージョン以降、UNION_MERGE ヒントを削除し、UNION_MERGE ヒントステートメントをサポートしていません。
UNION_MERGE ヒントは、クエリプランでのインデックスマージの実行方式を指定するために使用されます。有効な UNION_MERGE ヒントが指定された場合、OceanBaseデータベースは対応するインデックスマージ計画を直接選択します。
構文は以下のとおりです:
/*+ UNION_MERGE(table_name index_name_list) */
パラメータの説明:
table_name:テーブル名を指定します。index_name_list:インデックス名のリストを指定します。複数のインデックス名はスペースで区切ります。
例:
フルテキストインデックスを含むテーブル
tbl1を作成します。CREATE TABLE tbl1 ( col1 INT PRIMARY KEY, col2 INT, col3 VARCHAR(100), col4 VARCHAR(100), FULLTEXT INDEX ftidx3(col3), FULLTEXT INDEX ftidx4(col4) );UNION_MERGEヒントを使用して実行計画を確認します。クエリ内でUNION_MERGEヒントを使用し、テーブルtbl1とインデックスftidx3、ftidx4を指定します。EXPLAIN SELECT /*+UNION_MERGE(tbl1 ftidx3 ftidx4)*/ * FROM tbl1 WHERE col1 = 1 AND (MATCH(col3) AGAINST ("word1") OR MATCH(col4) AGAINST ("word1"));実行結果は次のとおりです:
+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +----------------------------------------------------------------------------------------------------------------------------------------------------------------+ | =========================================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | --------------------------------------------------------------------------- | | |0 |DISTRIBUTED INDEX MERGE SCAN|tbl1(ftidx3,ftidx4)|1 |45 | | | =========================================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output([tbl1.col1], [tbl1.col2], [tbl1.col3], [tbl1.col4]), filter([MATCH(tbl1.col3) AGAINST('word1') OR MATCH(tbl1.col4) AGAINST('word1')], [tbl1.col1 | | = 1]), rowset=16 | | access([tbl1.col1], [tbl1.col3], [tbl1.col4], [tbl1.col2]), partitions(p0) | | is_index_back=true, is_global_index=false, keep_ordering=true, use_index_merge=true, filter_before_indexback[false,false], | | index_name: ftidx3, range_cond(nil), filter(nil) | | index_name: ftidx4, range_cond(nil), filter(nil) | | lookup_filter([tbl1.col1 = 1], [MATCH(tbl1.col3) AGAINST('word1') OR MATCH(tbl1.col4) AGAINST('word1')]) | +----------------------------------------------------------------------------------------------------------------------------------------------------------------+ 14 rows in set実行結果の説明:
DISTRIBUTED INDEX MERGE SCAN:分散環境でインデックスマージのスキャン方式が使用されたことを示します。is_index_back=true:テーブルへの再アクセス操作が有効になっていることを示します。use_index_merge=true:インデックスマージが有効になっていることを示します。filter_before_indexback[false,false]:フィルター条件がテーブルへの再アクセス操作前に適用されなかったことを示します。
PUSH_SUBQ ヒント
PUSH_SUBQ ヒントは、オプティマイザーに対し、結合に書き換えられていないサブクエリを早期に実行するよう指示します。通常、これらのサブクエリは結合に書き換えられない場合、実行計画のすべてのテーブル結合計算の後に配置されます。サブクエリの計算コストが低く、大量のデータをフィルタリングできる場合、事前に実行することで計画のパフォーマンスが向上する可能性があります。ただし、サブクエリが結合(/+unnest/)に書き換えられている場合は、このヒントは無効です。適用シナリオは以下のとおりです:
- サブクエリの実行コストは低いものの、大量のデータを迅速にフィルタリングできる場合。
- サブクエリの結果を早期に利用してデータ範囲を絞り込む必要がある場合。
構文は以下のとおりです:
/*+ PUSH_SUBQ[(@qb_name)] */
パラメータの説明:
@qb_name:オプションのパラメータで、サブクエリのエイリアスを指定します(詳細については、前述のQB_NAMEパラメータを参照してください)。これにより、ヒントの対象を明確にします。省略した場合、デフォルトでヒントが含まれるサブクエリに対して有効になります。
例:
クエリ内で PUSH_SUBQ ヒントを使用して、オプティマイザーに対しサブクエリを早期に実行するよう指示し、tbl1 テーブルのデータを事前にフィルタリングします。
SELECT /*+ PUSH_SUBQ(@"SEL$2") */ *
FROM tbl1, tbl2
WHERE tbl1.col1 = (SELECT MAX(tbl3.col1)
FROM tbl3
WHERE tbl3.col2 = tbl2.col2);
NO_push_SUBQ ヒント
NOPush_SUBQ ヒントは PUSH_SUBQ の逆操作であり、オプティマイザーに対し、結合に書き換えられていないサブクエリを最後に実行するよう指示します。サブクエリのコストが高い、または行数を大幅に削減できない場合に適しています。適用シナリオは以下のとおりです:
- サブクエリの実行コストが高い、またはその結果がデータ量に与える影響が小さい場合。
- サブクエリの実行を他のフィルタリング条件が有効になってから遅延させ、入力データ量を削減する必要がある場合。
構文は以下のとおりです:
/*+ NO_PUSH_SUBQ[(@qb_name)] */
パラメータの説明:
@qb_name:オプションのパラメータで、サブクエリのエイリアスを指定します。
例:
クエリ内で NOPush_SUBQ ヒントを使用して、オプティマイザーに対しサブクエリの実行を最後に延期するよう指示します。
SELECT /*+ NO_PUSH_SUBQ */ *
FROM tbl1, tbl2
WHERE tbl1.col1 = (SELECT MAX(tbl3.col1)
FROM tbl3
WHERE tbl3.col2 = tbl2.col2);
OPT_PARAM ヒント
OPT_PARAM ヒントは、クエリレベルでオプティマイザー関連のパラメータやシステム変数を更新するために使用されます。
構文は以下のとおりです:
/*+ OPT_PARAM(parameter_name [,] parameter_value) */
パラメータの説明:
parameter_name:パラメータまたはシステム変数の名前です。parameter_value:指定する変数の値です。OPT_PARAMヒントは、以下のパラメータに有効です:rowsets_enabled: ベクトル化を有効/無効にします。データ型はVARCHARで、値の範囲は'TRUE'と'FALSE'です。値はシングルクォート('')で囲む必要があります。rowsets_max_rows: バッチ返却行数batch_sizeのサイズを設定します。データ型はINTで、値の範囲は[0, 65535]です。値はシングルクォート('')で囲むことはできません。enable_newsort: クエリで newsort 最適化を有効/無効にします。データ型はVARCHARで、値の範囲は'TRUE'と'FALSE'です。値はシングルクォート('')で囲む必要があります。use_part_sort_mgb: クエリで part sort merge group by を有効/無効にします。データ型はVARCHARで、値の範囲は'TRUE'と'FALSE'です。値はシングルクォート('')で囲む必要があります。enable_in_range_optimization: クエリで in 最適化を有効/無効にします。データ型はVARCHARで、値の範囲は'TRUE'と'FALSE'です。値はシングルクォート('')で囲む必要があります。xsolapi_generate_with_clause: クエリで cte 抽出リライトを有効/無効にします。データ型はVARCHARで、値の範囲は'TRUE'と'FALSE'です。値はシングルクォート('')で囲む必要があります。preserve_order_forPagination: ページネーションクエリの実行時にorder byの順序保持を追加するか、order byの追加を禁止します。データ型はVARCHARで、値の範囲は'TRUE'と'FALSE'です。値はシングルクォート('')で囲む必要があります。storage_card_estimation: ストレージ層で行を推定するかどうかを示します。データ型はVARCHARで、値の範囲は'TRUE'と'FALSE'です。値はシングルクォート('')で囲む必要があります。workarea_size_policy: SQL ワークエリアのサイズを手動または自動で調整するポリシーを設定します。データ型はVARCHARで、値の範囲は'MANUAL'が手動調整、'AUTO'が自動調整を示します。値はシングルクォート('')で囲む必要があります。enable_rich_vector_format: ベクトル化 2.0 を有効/無効にします(セッションレベルのパラメータ)。データ型はVARCHARで、値の範囲は'TRUE'と'FALSE'です。値はシングルクォート('')で囲む必要があります。spill_compression_codec: 一時マテリアライズが必要な演算子に対して使用する圧縮アルゴリズムを指定します。データ型はVARCHARで、値はNONE、LZ4、SNAPPY、ZLIB、ZSTDで、それぞれ異なる圧縮アルゴリズムを表します。デフォルトはNONEで、圧縮を行わないことを意味します。inlist_rewrite_threshold:inlistをvalues statementにリライトするトリガーを許可する定数の個数のしきい値です。データ型はINT64で、値の範囲は[1, 2147483647]です。orc_filter_pushdown_level:ステートメントレベルのORC外部テーブル条件のプッシュダウンレベルを制御します。parameter_valueの値は以下のとおりです:説明
OceanBaseデータベースでは、
OPT_PARAMヒントのparameter_nameパラメータは、V4.4.0バージョンからorc_filter_pushdown_levelの値をサポートしています。0:フィルタ条件のプッシュダウンを無効にします。1:ファイルレベルにプッシュダウンします。2:ストライプレベルにプッシュダウンします。3:row indexレベルにプッシュダウンします。4:Encodingレベルにプッシュダウンします。
parquet_filter_pushdown_level:ステートメントレベルのParquet外部テーブル条件のプッシュダウンレベルを制御します。parameter_valueの値は以下のとおりです:説明
OceanBaseデータベースでは、
OPT_PARAMヒントのparameter_nameパラメータは、V4.4.0バージョンからparquet_filter_pushdown_levelの値をサポートしています。0:フィルタ条件のプッシュダウンを無効にします。1:ファイルレベルにプッシュダウンします。2:RowGroupレベルにプッシュダウンします。3:Pageレベルにプッシュダウンします。4:Encodingレベルにプッシュダウンします。
例:
ステートメントレベルのORC外部テーブル条件のプッシュダウンレベルを制御します。
ORCフィルタ条件のプッシュダウン機能を無効にします。
SELECT /*+opt_param('orc_filter_pushdown_level', '0') */ * FROM ext_orc_tbl WHERE c1 = 1;ORC条件をファイルレベルにプッシュダウンします。
SELECT /*+opt_param('orc_filter_pushdown_level', '1') */ * FROM ext_orc_tbl WHERE c1 = 1;ORC条件をストライプレベルにプッシュダウンします。
SELECT /*+opt_param('orc_filter_pushdown_level', '2') */ * FROM ext_orc_tbl WHERE c1 = 1;ORC条件をrow indexレベルにプッシュダウンします。
SELECT /*+opt_param('orc_filter_pushdown_level', '3') */ * FROM ext_orc_tbl WHERE c1 = 1;ORC条件をencodingレベルにプッシュダウンします。
SELECT /*+opt_param('orc_filter_pushdown_level', '4') */ * FROM ext_orc_tbl WHERE c1 = 1;
ステートメントレベルのParquet外部テーブル条件のプッシュダウンレベルを制御します。
Parquetフィルタ条件のプッシュダウン機能を無効にします。
SELECT /*+opt_param('parquet_filter_pushdown_level', '0') */ * FROM ext_parquet_tbl WHERE c1 = 1;Parquet条件をファイルレベルにプッシュダウンします。
SELECT /*+opt_param('parquet_filter_pushdown_level', '1') */ * FROM ext_parquet_tbl WHERE c1 = 1;Parquet条件をRowGroupレベルにプッシュダウンします。
SELECT /*+opt_param('parquet_filter_pushdown_level', '2') */ * FROM ext_parquet_tbl WHERE c1 = 1;Parquet条件をPageレベルにプッシュダウンします。
SELECT /*+opt_param('parquet_filter_pushdown_level', '3') */ * FROM ext_parquet_tbl WHERE c1 = 1;Parquet条件をEncodingレベルにプッシュダウンします。
SELECT /*+opt_param('parquet_filter_pushdown_level', '4') */ * FROM ext_parquet_tbl WHERE c1 = 1;
INDEX_MERGE ヒント
INDEX_MERGE ヒントは、指定されたテーブルがインデックスマージ計画を使用するかどうかを制御します。指定されたインデックスがインデックスマージ計画を生成できない場合は、このヒントは無視されます。インデックスが指定されていない場合は、可能な限りインデックスマージ計画を試みます。
INDEX_MERGE ヒントを使用すると、_enable_index_merge 構成パラメータの値が False の場合でもインデックスマージ計画を生成できます。
構文は以下のとおりです:
/*+ INDEX_MERGE([@query_block_name] tbl_name [index_name [,index_name]...]) */
パラメータの説明:
@query_block_name:オプションです。このヒントが適用されるクエリブロック(query block)の名前を表します。省略した場合、デフォルトで現在のクエリのメインクエリブロックに適用されます。tbl_name:テーブル名を表します。index_name:オプションです。インデックス名を表し、複数のインデックス名を指定できます。- 指定されたテーブルの後に
index_nameパラメータがない場合、指定されたテーブルがインデックスマージ計画を使用するように制御します。 - 指定されたテーブルの後に
index_nameパラメータがある場合、指定されたテーブルが指定されたインデックス(Index)を使用してインデックスマージ計画を生成するように制御します。
- 指定されたテーブルの後に
例:
INDEX_MERGEヒントでインデックス名を指定します。obclient> SELECT /*+ INDEX_MERGE(t1 idx_c2 idx_c3) */ * FROM t1 WHERE c2 = 1 AND c3 = 1 AND c4 = 1;INDEX_MERGEヒントでインデックス名を指定しません。obclient> SELECT /*+ INDEX_MERGE(t1)*/ * FROM t1 WHERE c2 = 1 AND c3 = 1 AND c4 = 1;
NO_INDEX_MERGE ヒント
NO_INDEX_MERGE ヒントは、指定されたテーブルが指定されたインデックスを使用してインデックスマージ計画を生成しないように制御します。インデックスが指定されていない場合、そのテーブルがインデックスマージ計画を生成することを禁止します。
NO_INDEX_MERGE ヒントと INDEX_MERGE ヒントが競合する場合、これら2つのヒントは無視されます。
構文は以下のとおりです:
/*+ NO_INDEX_MERGE([@query_block_name] tbl_name [index_name [,index_name]...]) */
パラメータの説明:
@query_block_name:オプションです。このヒントが適用されるクエリブロック(query block)の名前を表します。省略した場合、デフォルトで現在のクエリのメインクエリブロックに適用されます。tbl_name:テーブル名を表します。index_name:オプションです。インデックス名を表し、複数のインデックス名を指定できます。- 指定されたテーブルの後に
index_nameパラメータがない場合、インデックスマージ計画を使用しないことを意味します。 - 指定されたテーブルの後に
index_nameパラメータがある場合、指定されたインデックス(Index)を使用してインデックスマージ計画を生成しないことを意味します。
- 指定されたテーブルの後に
例:
obclient> SELECT /*+ NO_INDEX_MERGE(t1)*/ * FROM t1
WHERE c2 = 1
AND c3 = 1
AND c4 = 1;