パラレルDMLは、パラレル実行メカニズムを利用して、大規模データベースのテーブルやインデックスに対する挿入、更新、削除などの操作の実行効率を向上させます。意思決定支援システム(DSS)向けのデータベースにおいては、パラレルDMLはクエリと更新機能を提供し、パラレルクエリ機能を補完します。OLTPデータベースにおいては、パラレルDML操作によりバッチ処理ジョブの実行が高速化されます。
パラレルDMLの設定
OceanBaseデータベースでは、SQLステートメントまたはセッション内でパラレルDMLを明示的に有効または無効にすることができます。
SQLステートメントでパラレルDMLを有効にする
SQLステートメントでパラレルDMLを有効にするには、ステートメント内に以下のヒントを挿入します:
/*+ ENABLE_PARALLEL_DML PARALLEL(3) */
一般的に、ENABLE_PARALLEL_DML ヒントと PARALLEL ヒントは組み合わせて使用する必要があります。ただし、ターゲットテーブルのスキーマでテーブルレベルの並列度が指定されている場合は、ENABLE_PARALLEL_DML ヒントのみを指定する必要があります。
例:
ENABLE_PARALLEL_DML ヒントと PARALLEL(n) パラメータを同時に使用して、並列度 n を指定します。ここで、n > 1 であり、並列度 dop=2 です。
テーブル
t1を作成します。CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT) NOPARALLEL;テーブル
t2を作成します。CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 11 PARTITION BY HASH(c1) PARTITIONS 3;テーブル
t3を作成します。CREATE TABLE t3 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 10 PARTITION BY HASH(c1) PARTITIONS 4;実行計画を確認します。
EXPLAIN INSERT /*+ ENABLE_PARALLEL_DML PARALLEL(2) */ INTO t1 SELECT * FROM t3;実行結果は次のとおりです:
+-------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +-------------------------------------------------------------------------------------------------------------------------------------------------------+ | ========================================================================= | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ------------------------------------------------------------------------- | | |0 |OPTIMIZER STATS MERGE | |1 |18 | | | |1 | PX COORDINATOR | |1 |18 | | | |2 | EXCHANGE OUT DISTR |:EX10001 |1 |18 | | | |3 | INSERT | |1 |17 | | | |4 | EXCHANGE IN DISTR | |1 |4 | | | |5 | EXCHANGE OUT DISTR (HASH)|:EX10000 |1 |4 | | | |6 | OPTIMIZER STATS GATHER | |1 |4 | | | |7 | SUBPLAN SCAN |ANONYMOUS_VIEW1|1 |4 | | | |8 | PX BLOCK ITERATOR | |1 |4 | | | |9 | TABLE SCAN |t3 |1 |4 | | | ========================================================================= | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=256 | | 1 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 | | 2 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 | | dop=2 | | 3 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil) | | columns([{t1: ({t1: (t1.c1, t1.c2)})}]), partitions(p0), | | column_values([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]) | | 4 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 | | 5 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 | | (#keys=1, [column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)]), dop=2 | | 6 - output([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]), filter(nil), rowset=256 | | 7 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=256 | | access([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]) | | 8 - output([t3.c1], [t3.c2]), filter(nil), rowset=256 | | 9 - output([t3.c1], [t3.c2]), filter(nil), rowset=256 | | access([t3.c1], [t3.c2]), partitions(p[0-3]) | | is_index_back=false, is_global_index=false, | | range_key([t3.c1]), range(MIN ; MAX)always true | +-------------------------------------------------------------------------------------------------------------------------------------------------------+ 34 rows in set
SQLステートメントでパラレルDMLを無効にする
パラレルDMLを無効にするには、ステートメント内に以下のヒントを挿入します。
/*+ DISABLE_PARALLEL_DML */
セッションでパラレルDMLが有効になっていても、指定されたSQLステートメント内でDISABLE_PARALLEL_DMLヒントを使用してパラレルDMLを無効にできます。
セッションでのパラレルDMLの有効化
デフォルトでは、SQLステートメントでPARALLELヒントを使用しても、パラレルDMLは有効になりません。そのため、セッション上でパラレルDMLを有効にする必要があります。
以下のSQLステートメントを実行して、セッションでパラレルDMLを有効にします:
SET _FORCE_PARALLEL_DML_DOP = n;
ここで、nは1より大きい。
ALTER SESSION ENABLE PARALLEL DML;
Oracleモードでは、セッション内で並列DMLを強制的に有効にする必要がある場合は、次のSQLステートメントを実行してください:
ALTER SESSION FORCE PARALLEL DML PARALLEL n;
例:
Oracleモードでセッション内で並列DMLを強制的に有効にします。
テーブル
t1を作成します。CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT) NOPARALLEL;テーブル
t2を作成します。CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 11 PARTITION BY HASH(c1) PARTITIONS 3;テーブル
t3を作成します。CREATE TABLE t3 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 10 PARTITION BY HASH(c1) PARTITIONS 4;セッション内で並列DMLを強制的に有効にします。
ALTER SESSION FORCE PARALLEL DML PARALLEL 6;実行計画を確認します。
EXPLAIN INSERT INTO t2 SELECT * FROM t3;実行結果は次のとおりです:
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ============================================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ------------------------------------------------------------------------------ | | |0 |OPTIMIZER STATS MERGE | |1 |16 | | | |1 | PX COORDINATOR | |1 |16 | | | |2 | EXCHANGE OUT DISTR |:EX10001 |1 |15 | | | |3 | INSERT | |1 |15 | | | |4 | EXCHANGE IN DISTR | |1 |2 | | | |5 | EXCHANGE OUT DISTR (PKEY HASH)|:EX10000 |1 |2 | | | |6 | OPTIMIZER STATS GATHER | |1 |2 | | | |7 | SUBPLAN SCAN |ANONYMOUS_VIEW1|1 |2 | | | |8 | PX BLOCK ITERATOR | |1 |2 | | | |9 | TABLE SCAN |T3 |1 |2 | | | ============================================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=256 | | 1 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256 | | 2 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256 | | dop=6 | | 3 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil) | | columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p[0-2]), | | column_values([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]) | | 4 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)], [PARTITION_ID]), filter(nil), | | rowset=256 | | 5 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)], [PARTITION_ID]), filter(nil), | | rowset=256 | | (#keys=1, [column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)]), dop=6 | | 6 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256 | | 7 - output([ANONYMOUS_VIEW1.C1], [ANONYMOUS_VIEW1.C2]), filter(nil), rowset=256 | | access([ANONYMOUS_VIEW1.C1], [ANONYMOUS_VIEW1.C2]) | | 8 - output([T3.C1], [T3.C2]), filter(nil), rowset=256 | | 9 - output([T3.C1], [T3.C2]), filter(nil), rowset=256 | | access([T3.C1], [T3.C2]), partitions(p[0-3]) | | is_index_back=false, is_global_index=false, | | range_key([T3.C1]), range(MIN ; MAX)always true | +------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 36 rows in set
注意すべき点として、SQLステートメントで並列DMLを有効にする際、一般的にはHintで指定された並列度を使用してクエリを実行し、その優先順位はセッション内で強制的に指定された並列度よりも高いことが挙げられます。
例:
テーブル
t1を作成します。CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT) NOPARALLEL;テーブル
t2を作成します。CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 11 PARTITION BY HASH(c1) PARTITIONS 3;テーブル
t3を作成します。CREATE TABLE t3 (c1 INT PRIMARY KEY, c2 INT) PARALLEL 10 PARTITION BY HASH(c1) PARTITIONS 4;セッション内で並列DMLを強制的に有効にします。
ALTER SESSION FORCE PARALLEL DML PARALLEL 6;実行計画を確認します。
EXPLAIN INSERT /*+ PARALLEL(3) */ INTO t2 SELECT * FROM t3;実行結果は次のとおりです:
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ============================================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ------------------------------------------------------------------------------ | | |0 |OPTIMIZER STATS MERGE | |1 |17 | | | |1 | PX COORDINATOR | |1 |17 | | | |2 | EXCHANGE OUT DISTR |:EX10001 |1 |17 | | | |3 | INSERT | |1 |16 | | | |4 | EXCHANGE IN DISTR | |1 |3 | | | |5 | EXCHANGE OUT DISTR (PKEY HASH)|:EX10000 |1 |3 | | | |6 | OPTIMIZER STATS GATHER | |1 |3 | | | |7 | SUBPLAN SCAN |ANONYMOUS_VIEW1|1 |3 | | | |8 | PX BLOCK ITERATOR | |1 |3 | | | |9 | TABLE SCAN |T3 |1 |3 | | | ============================================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=256 | | 1 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256 | | 2 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256 | | dop=3 | | 3 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil) | | columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p[0-2]), | | column_values([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]) | | 4 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)], [PARTITION_ID]), filter(nil), | | rowset=256 | | 5 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)], [PARTITION_ID]), filter(nil), | | rowset=256 | | (#keys=1, [column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)]), dop=3 | | 6 - output([column_conv(NUMBER,PS:(-1,0),NOT NULL,ANONYMOUS_VIEW1.C1)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.C2)]), filter(nil), rowset=256 | | 7 - output([ANONYMOUS_VIEW1.C1], [ANONYMOUS_VIEW1.C2]), filter(nil), rowset=256 | | access([ANONYMOUS_VIEW1.C1], [ANONYMOUS_VIEW1.C2]) | | 8 - output([T3.C1], [T3.C2]), filter(nil), rowset=256 | | 9 - output([T3.C1], [T3.C2]), filter(nil), rowset=256 | | access([T3.C1], [T3.C2]), partitions(p[0-3]) | | is_index_back=false, is_global_index=false, | | range_key([T3.C1]), range(MIN ; MAX)always true | +------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 36 rows in set
セッション内でパラレルDMLを無効にする
次のSQLステートメントを実行して、セッション内でパラレルDMLを無効にします。
SET _FORCE_PARALLEL_DML_DOP = 1;
ALTER SESSION DISABLE PARALLEL DML;
例と実行計画の解析
パーティション単位の並列更新
以下のSQLステートメントに基づいて、テーブルパーティションの並列処理機能を説明します。
テストテーブル
branch_sp_tbl_srcを作成します。CREATE TABLE branch_sp_tbl_src(id INT PRIMARY KEY, v INT) PARTITION BY KEY(id) PARTITIONS 4;テストテーブル
branch_sp_tbl_destを作成します。CREATE TABLE branch_sp_tbl_dest LIKE branch_sp_tbl_src;実行計画を確認します。
以下のSQLステートメントを実行すると、この挿入操作の実行方法が示されます。
obclient [test]> EXPLAIN BASIC INSERT /*+enable_parallel_dml parallel(100) query_timeout(1000000000)*/ INTO branch_sp_tbl_dest SELECT id, v FROM branch_sp_tbl_src ON DUPLICATE KEY UPDATE v = v + 1;実行結果は次のとおりです:
+-------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +-------------------------------------------------------------------------------------------------------------------------------------+ | ================================================ | | |ID|OPERATOR |NAME | | | ------------------------------------------------ | | |0 |PX COORDINATOR | | | | |1 |└─EXCHANGE OUT DISTR |:EX10000 | | | |2 | └─PX PARTITION ITERATOR| | | | |3 | └─INSERT_UP | | | | |4 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1 | | | |5 | └─TABLE FULL SCAN|branch_sp_tbl_src| | | ================================================ | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=16 | | 1 - output(nil), filter(nil), rowset=16 | | dop=100 | | 2 - output(nil), filter(nil), rowset=16 | | partition wise, force partition granule | | 3 - output(nil), filter(nil) | | columns([{branch_sp_tbl_dest: ({branch_sp_tbl_dest: (branch_sp_tbl_dest.id, branch_sp_tbl_dest.v)})}]), partitions(p[0-3]), | | column_values([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.id)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.v)]), | | update([branch_sp_tbl_dest.v=column_conv(INT,PS:(11,0),NULL,cast(branch_sp_tbl_dest.v + 1, INT(-1, 0)))]) | | 4 - output([ANONYMOUS_VIEW1.id], [ANONYMOUS_VIEW1.v]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.id], [ANONYMOUS_VIEW1.v]) | | 5 - output([branch_sp_tbl_src.id], [branch_sp_tbl_src.v]), filter(nil), rowset=16 | | access([branch_sp_tbl_src.id], [branch_sp_tbl_src.v]), partitions(p[0-3]) | | is_index_back=false, is_global_index=false, | | range_key([branch_sp_tbl_src.id]), range(MIN ; MAX)always true | +-------------------------------------------------------------------------------------------------------------------------------------+ 27 rows in setクエリプランにおける演算子の分析は以下のとおりです:
- 演算子0:これはパラレル実行コーディネーターであり、パラレル実行プロセスを管理します。
- 演算子1:データが異なる実行ノード間で分散されることを示します。
- 演算子2:クエリがパーティションをイテレーションすることを示します。「partition wise」は、クエリが各パーティション間のデータをインテリジェントに処理することを意味します。
- 演算子3:挿入または更新操作を示します。挿入キーがテーブルに存在しない場合は挿入操作を実行し、存在する場合は更新操作を実行します。
- 演算子4と5:
branch_sp_tbl_srcという名前のテーブルに対してフルスキャンを実行することを示します。このテーブルはデータソースであり、そこからデータを選択して挿入操作を行います。
パラレルDMLによる関連更新
説明
OceanBaseデータベースV4.3.x系では、パラレルDMLはV4.3.5バージョンから、複数テーブルの結合(JOIN)を用いた関連更新機能をサポートしています。
関連更新とは、UPDATE ステートメント内で複数テーブルの結合操作を使用し、関連テーブルのデータに基づいてターゲットテーブルを更新することを指します。パラレルDML機能を利用することで、大規模なデータ更新操作のパフォーマンスを大幅に向上させることができます。
例:
以下の手順は、パラレルDMLを使用して関連更新機能を実現する方法を示しています。
テスト用のテーブル
customersとordersを作成します。CREATE TABLE customers ( id INT PRIMARY KEY, name VARCHAR(50), customer_level VARCHAR(10) );CREATE TABLE orders ( order_id INT PRIMARY KEY, customer_id INT, discount DECIMAL(3, 2), amount DECIMAL(10, 2) );テストデータを挿入します。
customersテーブルに顧客データを挿入します:INSERT INTO customers (id, name, customer_level) VALUES (1, 'Alice', 'VIP'), (2, 'Bob', 'NORMAL'), (3, 'Charlie', 'OTHER');ordersテーブルに注文データを挿入します:INSERT INTO orders (order_id, customer_id, discount, amount) VALUES (101, 1, NULL, 1000.00), (102, 2, NULL, 2000.00), (103, 3, NULL, 1500.00), (104, 1, NULL, 3000.00), (105, 2, NULL, 2500.00);
パラレルDMLによる関連更新を実行します。
EXPLAINを使用して、パラレルDMLによる関連更新の実行計画を確認します。PARALLELヒントを使用して並列度を4に指定し、customersテーブルの顧客ランク(customer_level)に基づいて、ordersテーブルの割引フィールド(discount)を更新します。EXPLAIN UPDATE /*+ PARALLEL(4) */ orders o JOIN customers c ON o.customer_id = c.id SET o.discount = CASE WHEN c.customer_level = 'VIP' THEN 0.9 WHEN c.customer_level = 'NORMAL' THEN 0.95 ELSE 1.0 END;実行結果は次のとおりです:
+------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ========================================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | -------------------------------------------------------------------------- | | |0 |DISTRIBUTED UPDATE | |3 |50 | | | |1 |└─PX COORDINATOR | |3 |3 | | | |2 | └─EXCHANGE OUT DISTR |:EX10001|3 |3 | | | |3 | └─SHARED HASH JOIN | |3 |3 | | | |4 | ├─EXCHANGE IN DISTR | |3 |2 | | | |5 | │ └─EXCHANGE OUT DISTR (BC2HOST)|:EX10000|3 |2 | | | |6 | │ └─PX BLOCK ITERATOR | |3 |1 | | | |7 | │ └─TABLE FULL SCAN |c |3 |1 | | | |8 | └─PX BLOCK ITERATOR | |5 |1 | | | |9 | └─TABLE FULL SCAN |o |5 |1 | | | ========================================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil) | | table_columns([{o: ({orders: (o.order_id, o.customer_id, o.discount, o.amount)})}]), | | update([o.discount=column_conv(DECIMAL_INT,PS:(3,2),NULL,CASE WHEN c.customer_level = 'VIP' THEN cast(0.9, DECIMAL_INT(3, 2)) WHEN c.customer_level | | = 'NORMAL' THEN 0.95 ELSE cast(1.0, DECIMAL_INT(3, 2)) END)]) | | 1 - output([o.order_id], [o.customer_id], [o.discount], [o.amount], [c.customer_level]), filter(nil), rowset=16 | | 2 - output([o.order_id], [o.customer_id], [o.discount], [o.amount], [c.customer_level]), filter(nil), rowset=16 | | dop=4 | | 3 - output([o.order_id], [o.customer_id], [o.discount], [o.amount], [c.customer_level]), filter(nil), rowset=16 | | equal_conds([o.customer_id = c.id]), other_conds(nil) | | 4 - output([c.id], [c.customer_level]), filter(nil), rowset=16 | | 5 - output([c.id], [c.customer_level]), filter(nil), rowset=16 | | dop=4 | | 6 - output([c.id], [c.customer_level]), filter(nil), rowset=16 | | 7 - output([c.id], [c.customer_level]), filter(nil), rowset=16 | | access([c.id], [c.customer_level]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([c.id]), range(MIN ; MAX)always true | | 8 - output([o.order_id], [o.customer_id], [o.discount], [o.amount]), filter(nil), rowset=16 | | 9 - output([o.order_id], [o.customer_id], [o.discount], [o.amount]), filter(nil), rowset=16 | | access([o.order_id], [o.customer_id], [o.discount], [o.amount]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([o.order_id]), range(MIN ; MAX)always true | +------------------------------------------------------------------------------------------------------------------------------------------------------------+ 38 rows in set
制限事項と注意点
- パラレルDMLが無効になっている場合、SQL文で
PARALLELヒントを使用しても、パラレルDMLは実行されません。 - セッションでパラレルDMLが有効になっている場合、そのセッション内のすべてのDML文に対するパラレル実行が有効になります。SQL文が
ENABLE_PARALLEL_DMLヒントによってパラレルDMLを有効にした場合、パラレル実行は指定された文にのみ適用されます。ただし、パラレル属性を持つテーブルがない場合や、パラレル操作の制限に違反した場合は、パラレルDMLが有効になっていても、DML操作は引き続きシリアル実行されます。
パラレルDMLがサポートされるシナリオ
| シナリオ | INSERT | UPDATE | DELETE | MERGE INTO |
|---|---|---|---|---|
テーブルに外部キー/トリガー(Trigger)/PL UDF(ユーザー定義関数)/一意インデックスが存在する場合
説明トリガーが実際にトリガーされるかどうかは明確ではありません。トリガーがDML操作と無関係である場合、トリガーはトリガーされず、並列DMLが引き続き実行されます。例えば、 |
不支持 | 不支持 | 不支持 | 不支持 |
| 複数テーブルDML | INSERT ALL構文は、並列DMLをサポートしていません |
UPDATE の並列処理をサポートします。
説明
|
UPDATEと同じ | 構文はサポートされていません |
| 自動インクリメント列 | 一部のシナリオでは並列DMLがサポートされており、詳細については以下の例を参照してください。 | サポート | サポート | サポート (seq) |
| ArrayBindingバッチ最適化 | 不支持 | 不支持 | 不支持 | 不支持 |
| USER_VARIABLEの使用 | 不支持 | 不支持 | 不支持 | 不支持 |
| IGNORE | 不支持 | 不支持 | 不支持 | 構文はサポートされていません |
| DBLink | 不支持 | 不支持 | 不支持 | 不支持 |
| その他 | 以下のステートメントは並列DMLをサポートしていません:
|
ON UPDATE CURRENT_TIMESTAMP列を含むものはサポートされていません |
INSERT でテーブルに書き込む際、自動インクリメント列が存在する場合、その自動インクリメント列が主キーまたはパーティションキーであり、かつその列が指定されている場合、パラレルDMLはサポートされません。
例:
テーブル
tbl1を作成します。このテーブルでは、列col1が自動インクリメント列であり、主キーとして指定されています。CREATE TABLE tbl1(col1 INT AUTO_INCREMENT PRIMARY KEY, col2 INT, col3 INT);テーブル
tbl2を作成します。このテーブルでは、列col1が自動インクリメント列です。CREATE TABLE tbl1(col1 INT AUTO_INCREMENT, col2 INT, col3 INT);テーブル
tbl3を作成します。CREATE TABLE tbl3(col1 INT, col2 INT, col3 INT);INSERTでデータを書き込む際、自動インクリメント列col1が主キーであるため、パラレルDMLはサポートされません。INSERT /*+enable_parallel_dml parallel(3)*/ INTO tbl1 SELECT * FROM tbl3;INSERTでデータを書き込む際、列col1が指定されていないため、パラレルDMLはサポートされます。INSERT /*+enable_parallel_dml parallel(3)*/ INTO tbl1(col2, col3) SELECT col2, col3 FROM tbl3;INSERTでデータを書き込む際、列col1が単なる自動インクリメント列であるため、パラレルDMLはサポートされます。INSERT /*+enable_parallel_dml parallel(3)*/ INTO tbl2 SELECT * FROM tbl3;