| ヒントタイプ | 説明 |
|---|---|
| PQ_SUBQUERY | 並列処理におけるサブクエリの動作に対する詳細な制御を提供します。 |
| PUSH_SUBQ | オプティマイザーが結合に書き換えられていないサブクエリを早期に実行するよう指示します。
説明OceanBaseデータベースV4.3.5では、V4.3.5 BP2以降のバージョンから |
| NO_push_SUBQ | PUSH_SUBQ の逆操作であり、オプティマイザーが結合に書き換えられていないサブクエリを最後に実行するようにします。
説明OceanBaseデータベースV4.3.5では、V4.3.5 BP2以降のバージョンから |
PQ_SUBQUERY ヒント
PQ_SUBQUERY ヒントは、パラレル処理におけるサブクエリの動作を細かく制御するためのものであり、特に分散データ配布が関与する場合において、パラレルクエリ(Parallel Query, PQ)環境下でオプティマイザーがサブクエリをどのように処理するかを指示します。
PQ_SUBQUERY ヒントには、主に2種類の制御方法が含まれます:非厳密制御方式と厳密制御方式です。
精密な制御方式ではない場合
構文
/*+ PQ_SUBQUERY ([ @qb_name ] [table_list] [op_order_no] sub_qb_name_list method_list) */
パラメータの説明
@qb_name: オプション。現在のクエリブロックのエイリアスを指定します。table_list: オプション。表を表すリストで、接続内で割り当てられたサブプランフィルター方式でのみ使用されます。op_order_no: 操作ノードの順序番号です。sub_qb_name_list: サブクエリブロックのエイリアスリストです。method_list: データの分散ディストリビューション方式。具体的なディストリビューション方法は以下のとおりです:DIST_BASIC_METHOD: 特定の方法を指定しません。DIST_PARTITION_WISE: データをパーティション単位で分散します。NONE NONEメソッドを使用します。DIST_PULL_TO_LOCAL: データをローカルにプルします。LOCAL LOCALメソッドを使用します。DIST_PARTITION_NONE: パーティション処理を行いますが、その後の方法が指定されていないため、PARTITION NONEを使用します。DIST_NONE_ALL: パーティション処理を行わず、データをすべてのノードにブロードキャストします。NONE ALLを使用します。
例
PQ_SUBQUERY(@SEL$1 0 SEL$1 PARTITION NONE) -- PQ_SUBQUERY(SEL$1)と省略可能
PQ_SUBQUERY(@SEL$1 1 SEL$2 PARTITION NONE)
CREATE TABLE t1(c1 INT, c2 INT, c3 INT, c4 INT)
PARTITION BY HASH(c1) PARTITIONS 10;
EXPLAIN
SELECT
(SELECT t_inner.c1 FROM t1 t_inner WHERE t_inner.c1 = t_outer.c3) AS a
FROM t1 t_outer
ORDER BY c3;
実行結果は次のとおりです:
+--------------------------------------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------------------------------------+
| ========================================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| -------------------------------------------------------------------------- |
| |0 |PX COORDINATOR | |3 |157 | |
| |1 |└─EXCHANGE OUT DISTR |:EX10002|3 |156 | |
| |2 | └─SUBPLAN FILTER | |3 |155 | |
| |3 | ├─EXCHANGE IN DISTR | |3 |42 | |
| |4 | │ └─EXCHANGE OUT DISTR (PKEY) |:EX10001|3 |41 | |
| |5 | │ └─EXCHANGE IN MERGE SORT DISTR| |3 |40 | |
| |6 | │ └─EXCHANGE OUT DISTR |:EX10000|3 |40 | |
| |7 | │ └─SORT | |3 |39 | |
| |8 | │ └─PX PARTITION ITERATOR | |3 |38 | |
| |9 | │ └─TABLE FULL SCAN |t_outer |3 |38 | |
| |10| └─PX PARTITION ITERATOR | |1 |38 | |
| |11| └─TABLE FULL SCAN |t_inner |1 |38 | |
| ========================================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([INTERNAL_FUNCTION(subquery(1))]), filter(nil), rowset=16 |
| 1 - output([INTERNAL_FUNCTION(subquery(1))]), filter(nil), rowset=16 |
| dop=1 |
| 2 - output([subquery(1)]), filter(nil), rowset=16 |
| exec_params_([t_outer.c3(:0)]), onetime_exprs_(nil), init_plan_idxs_(nil), use_batch=false |
| 3 - output([t_outer.c3]), filter(nil), rowset=16 |
| 4 - output([t_outer.c3]), filter(nil), rowset=16 |
| (#keys=1, [t_outer.c3]), is_single, dop=1 |
| 5 - output([t_outer.c3]), filter(nil), rowset=16 |
| sort_keys([t_outer.c3, ASC]) |
| 6 - output([t_outer.c3]), filter(nil), rowset=16 |
| dop=1 |
| 7 - output([t_outer.c3]), filter(nil), rowset=16 |
| sort_keys([t_outer.c3, ASC]) |
| 8 - output([t_outer.c3]), filter(nil), rowset=16 |
| force partition granule |
| 9 - output([t_outer.c3]), filter(nil), rowset=16 |
| access([t_outer.c3]), partitions(p[0-9]) |
| is_index_back=false, is_global_index=false, |
| range_key([t_outer.__pk_increment]), range(MIN ; MAX)always true |
| 10 - output([t_inner.c1]), filter(nil), rowset=16 |
| affinitize, partition wise, force partition granule |
| 11 - output([t_inner.c1]), filter([t_inner.c1 = :0]), rowset=16 |
| access([t_inner.c1]), partitions(p[0-9]) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([t_inner.__pk_increment]), range(MIN ; MAX)always true |
+--------------------------------------------------------------------------------------------------+
44 rows in set
厳密な制御方式
構文
/*+ PQ_SUBQUERY ([ @qb_name ] win_group ...) */
パラメータの説明
win_group: (インデックスリスト) ウィンドウ関数のグループ化および内部動作を宣言するタプル。dist_method: 分散実行方式を指定します。オプションは上記と同じです。PARTITION_SORT: ハッシュ分散実行(HASH)または分散実行なし(NONE)の場合にパーティションソートアルゴリズムを適用するかどうか。デフォルトでは使用されません。PUSHDOWN: ハッシュ分散実行を使用する場合、ウィンドウ関数のダウンプッシュを適用するかどうか。
例
PQ_SUBQUERY (@SEL$1 (t_a t_b t_c) 0 SEL$2 PARTITION NONE)
-- 省略可能であり、PQ_SUBQUERY ((t_a t_b t_c) SEL$2 PARTITION NONE) と表記できます。
EXPLAIN
SELECT /*+ PQ_SUBQUERY (@SEL$1 (t_a, t_b, t_c) 0 SEL$2 PARTITION NONE) */
t_a.c1 AS a_c1,
t_b.c1 AS b_c1,
t_c.c1 AS c_c1,
t_d.c1 AS d_c1
FROM t1 t_a
LEFT JOIN t1 t_b ON t_a.c3 = t_b.c4
INNER JOIN t1 t_c ON t_a.c1 = t_c.c1
RIGHT JOIN t1 t_d ON t_a.c3 = t_d.c4
WHERE t_a.c1 = t_d.c3
AND t_c.c2 + (SELECT c4 FROM t1 WHERE c1 = t_c.c3 AND c2 = t_a.c2 AND c3 = t_b.c1) = t_a.c3;
実行結果は次のとおりです:
+--------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+--------------------------------------------------------------------------------------------------------------------------+
| =========================================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| --------------------------------------------------------------------------- |
| |0 |PX COORDINATOR | |1 |302 | |
| |1 |└─EXCHANGE OUT DISTR |:EX10004|1 |300 | |
| |2 | └─SUBPLAN FILTER | |1 |298 | |
| |3 | ├─EXCHANGE IN DISTR | |3 |184 | |
| |4 | │ └─EXCHANGE OUT DISTR (PKEY) |:EX10003|3 |180 | |
| |5 | │ └─HASH JOIN | |3 |172 | |
| |6 | │ ├─EXCHANGE IN DISTR | |3 |43 | |
| |7 | │ │ └─EXCHANGE OUT DISTR |:EX10000|3 |42 | |
| |8 | │ │ └─PX PARTITION ITERATOR | |3 |38 | |
| |9 | │ │ └─TABLE FULL SCAN |t_d |3 |38 | |
| |10| │ └─HASH RIGHT OUTER JOIN | |3 |128 | |
| |11| │ ├─EXCHANGE IN DISTR | |3 |41 | |
| |12| │ │ └─EXCHANGE OUT DISTR |:EX10001|3 |40 | |
| |13| │ │ └─PX PARTITION ITERATOR| |3 |38 | |
| |14| │ │ └─TABLE FULL SCAN |t_b |3 |38 | |
| |15| │ └─EXCHANGE IN DISTR | |3 |86 | |
| |16| │ └─EXCHANGE OUT DISTR |:EX10002|3 |84 | |
| |17| │ └─PX PARTITION ITERATOR| |3 |78 | |
| |18| │ └─HASH JOIN | |3 |78 | |
| |19| │ ├─TABLE FULL SCAN |t_a |3 |38 | |
| |20| │ └─TABLE FULL SCAN |t_c |3 |38 | |
| |21| └─PX PARTITION ITERATOR | |1 |39 | |
| |22| └─TABLE FULL SCAN |t1 |1 |39 | |
| =========================================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([INTERNAL_FUNCTION(t_a.c1, t_b.c1, t_c.c1, t_d.c1)]), filter(nil), rowset=16 |
| 1 - output([INTERNAL_FUNCTION(t_a.c1, t_b.c1, t_c.c1, t_d.c1)]), filter(nil), rowset=16 |
| dop=1 |
| 2 - output([t_b.c1], [t_a.c1], [t_d.c1], [t_c.c1]), filter([t_c.c2 + subquery(1) = t_a.c3]), rowset=16 |
| exec_params_([t_c.c3(:0)], [t_a.c2(:1)], [t_b.c1(:2)]), onetime_exprs_(nil), init_plan_idxs_(nil), use_batch=false |
| 3 - output([t_b.c1], [t_c.c3], [t_a.c2], [t_a.c1], [t_a.c3], [t_d.c1], [t_c.c1], [t_c.c2]), filter(nil), rowset=16 |
| 4 - output([t_b.c1], [t_c.c3], [t_a.c2], [t_a.c1], [t_a.c3], [t_d.c1], [t_c.c1], [t_c.c2]), filter(nil), rowset=16 |
| (#keys=1, [t_c.c3]), is_single, dop=1 |
| 5 - output([t_b.c1], [t_c.c3], [t_a.c2], [t_a.c1], [t_a.c3], [t_d.c1], [t_c.c1], [t_c.c2]), filter(nil), rowset=16 |
| equal_conds([t_a.c1 = t_d.c3], [t_a.c3 = t_d.c4]), other_conds(nil) |
| 6 - output([t_d.c1], [t_d.c4], [t_d.c3]), filter(nil), rowset=16 |
| 7 - output([t_d.c1], [t_d.c4], [t_d.c3]), filter(nil), rowset=16 |
| dop=1 |
| 8 - output([t_d.c1], [t_d.c4], [t_d.c3]), filter(nil), rowset=16 |
| force partition granule |
| 9 - output([t_d.c1], [t_d.c4], [t_d.c3]), filter(nil), rowset=16 |
| access([t_d.c1], [t_d.c4], [t_d.c3]), partitions(p[0-9]) |
| is_index_back=false, is_global_index=false, |
| range_key([t_d.__pk_increment]), range(MIN ; MAX)always true |
| 10 - output([t_b.c1], [t_c.c3], [t_a.c2], [t_a.c1], [t_a.c3], [t_c.c1], [t_c.c2]), filter(nil), rowset=16 |
| equal_conds([t_a.c3 = t_b.c4]), other_conds(nil) |
| 11 - output([t_b.c1], [t_b.c4]), filter(nil), rowset=16 |
| 12 - output([t_b.c1], [t_b.c4]), filter(nil), rowset=16 |
| dop=1 |
| 13 - output([t_b.c1], [t_b.c4]), filter(nil), rowset=16 |
| force partition granule |
| 14 - output([t_b.c1], [t_b.c4]), filter(nil), rowset=16 |
| access([t_b.c1], [t_b.c4]), partitions(p[0-9]) |
| is_index_back=false, is_global_index=false, |
| range_key([t_b.__pk_increment]), range(MIN ; MAX)always true |
| 15 - output([t_c.c3], [t_a.c2], [t_a.c1], [t_a.c3], [t_c.c1], [t_c.c2]), filter(nil), rowset=16 |
| 16 - output([t_c.c3], [t_a.c2], [t_a.c1], [t_a.c3], [t_c.c1], [t_c.c2]), filter(nil), rowset=16 |
| dop=1 |
| 17 - output([t_c.c3], [t_a.c2], [t_a.c1], [t_a.c3], [t_c.c1], [t_c.c2]), filter(nil), rowset=16 |
| partition wise, force partition granule |
| 18 - output([t_c.c3], [t_a.c2], [t_a.c1], [t_a.c3], [t_c.c1], [t_c.c2]), filter(nil), rowset=16 |
| equal_conds([t_a.c1 = t_c.c1]), other_conds(nil) |
| 19 - output([t_a.c1], [t_a.c3], [t_a.c2]), filter(nil), rowset=16 |
| access([t_a.c1], [t_a.c3], [t_a.c2]), partitions(p[0-9]) |
| is_index_back=false, is_global_index=false, |
| range_key([t_a.__pk_increment]), range(MIN ; MAX)always true |
| 20 - output([t_c.c1], [t_c.c3], [t_c.c2]), filter(nil), rowset=16 |
| access([t_c.c1], [t_c.c3], [t_c.c2]), partitions(p[0-9]) |
| is_index_back=false, is_global_index=false, |
| range_key([t_c.__pk_increment]), range(MIN ; MAX)always true |
| 21 - output([t1.c4]), filter(nil), rowset=16 |
| affinitize, partition wise, force partition granule |
| 22 - output([t1.c4]), filter([t1.c1 = :0], [t1.c2 = :1], [t1.c3 = :2]), rowset=16 |
| access([t1.c1], [t1.c2], [t1.c3], [t1.c4]), partitions(p[0-9]) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false,false,false], |
| range_key([t1.__pk_increment]), range(MIN ; MAX)always true |
+--------------------------------------------------------------------------------------------------------------------------+
80 rows in set
PUSH_SUBQ ヒント
説明
OceanBaseデータベースV4.3.5では、V4.3.5 BP2バージョンから 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 ヒント
説明
OceanBaseデータベースV4.3.5では、V4.3.5 BP2バージョンから NO_PUSH_SUBQ ヒントがサポートされています。
NO_push_SUBQ ヒントは PUSH_SUBQ の逆の操作であり、オプティマイザーが結合に書き換えられなかったサブクエリを最後に実行するようにします。サブクエリのコストが高い場合や、行数を大幅に削減できない場合に適しています。適用シナリオは以下のとおりです:
- サブクエリの実行コストが高い、またはその結果がデータ量に与える影響が小さい場合。
- サブクエリの実行を他のフィルタ条件が有効になってから遅延させ、入力データ量を削減する必要がある場合。
構文は以下のとおりです:
/*+ NO_PUSH_SUBQ[(@qb_name)] */
パラメータの説明:
@qb_name:オプションのパラメータで、サブクエリのエイリアスを指定します。
例:
クエリ内で NO-push_SUBQ ヒントを使用して、オプティマイザーにサブクエリの実行を最後に延期するよう指示します。
SELECT /*+ NO_PUSH_SUBQ */ *
FROM tbl1, tbl2
WHERE tbl1.col1 = (SELECT MAX(tbl3.col1)
FROM tbl3
WHERE tbl3.col2 = tbl2.col2);