首批通过分布式安全可靠测评,为关键业务系统打造
使用 INSERT INTO SELECT 语句旁路导入数据
更新时间:2024-09-08 23:00:00
INSERT INTO SELECT 语句通过 Hint 使用 append/direct() 加上 enable_parallel_dml 来走旁路导入。
全量旁路导入
使用限制
只支持 PDML(Parallel Data Manipulation Language,并行数据操纵语言),非 PDML 不能用旁路导入。有关并行 DML 的更多信息,参见 并行 DML。
在导入过程中无法同时执行两个写操作语句(即不能同时写一个表),因为导入过程中会先加表锁,并且整个导入过程中只能进行读操作。
不支持在触发器(Trigger)使用。
不支持含有生成列的表(某些索引会产生隐藏生成列,例如 KEY
idx_c2(c2(16)) GLOBAL)。不支持 Liboblog 和闪回查询(Flashback Query)。
旁路导入属于 DDL 语句,无法在多行事务(包含多个操作的事务)中执行。
- 不能在 Begin 中执行。
- Autocommit 必须设置为 1。
语法
INSERT /*+ [APPEND |direct(need_sort,max_error,'full')] enable_parallel_dml parallel(N) */ INTO table_name select_sentence
更多 INSERT INTO 语法的信息,请参见 INSERT(MySQL 模式) 和 INSERT(Oracle 模式)。
参数解释:
| 参数 | 描述 |
|---|---|
| APPEND | direct() | 使用 Hint 启用旁路导入功能。
|
| enable_parallel_dml parallel(N) | 加载数据的并行度。
说明一般情况下, |
| parallel(N) | 加载数据的并行度,必填项,取值是大于 1 的整数。 |
示例
使用旁路导入将表 tbl2 中的部分数据导入到 tbl1 中。
obclient [test]> SELECT * FROM tbl1;
Empty set
obclient [test]> SELECT * FROM tbl2;
+------+------+------+
| col1 | col2 | col3 |
+------+------+------+
| 1 | a1 | 11 |
| 2 | a2 | 22 |
| 3 | a3 | 33 |
+------+------+------+
3 rows in set
obclient [test]> INSERT /*+ direct(true, 0, 'full') enable_parallel_dml parallel(16) */ INTO tbl1 SELECT t2.col1,t2.col3 FROM tbl2 t2;
Query OK, 3 rows affected
Records: 3 Duplicates: 0 Warnings: 0
obclient [test]> SELECT * FROM tbl1;
+------+------+
| col1 | col2 |
+------+------+
| 1 | 11 |
| 2 | 22 |
| 3 | 33 |
+------+------+
3 rows in set
在 EXPLAIN EXTENDED 语句的返回结果的 Note 中,查看是否通过旁路导入写入的数据。
obclient [test]> EXPLAIN EXTENDED INSERT /*+ direct(true, 0, 'full') enable_parallel_dml parallel(16) */ INTO tbl1 SELECT t2.col1,t2.col3 FROM tbl2 t2;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| =========================================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| --------------------------------------------------------------------------- |
| |0 |OPTIMIZER STATS MERGE | |3 |27 | |
| |1 | PX COORDINATOR | |3 |27 | |
| |2 | EXCHANGE OUT DISTR |:EX10001 |3 |27 | |
| |3 | INSERT | |3 |26 | |
| |4 | EXCHANGE IN DISTR | |3 |1 | |
| |5 | EXCHANGE OUT DISTR (RANDOM)|:EX10000 |3 |1 | |
| |6 | OPTIMIZER STATS GATHER | |3 |1 | |
| |7 | SUBPLAN SCAN |ANONYMOUS_VIEW1|3 |1 | |
| |8 | PX BLOCK ITERATOR | |3 |1 | |
| |9 | TABLE SCAN |t2 |3 |1 | |
| =========================================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output(nil), filter(nil), rowset=256 |
| 1 - output([column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7f0ba6a51800))(0x7f0ba6a522c0)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7f0ba6a51ac0))(0x7f0ba6a59630)]), |
| filter(nil), rowset=256 |
| 2 - output([column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7f0ba6a51800))(0x7f0ba6a522c0)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7f0ba6a51ac0))(0x7f0ba6a59630)]), |
| filter(nil), rowset=256 |
| dop=16 |
| 3 - output([column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7f0ba6a51800))(0x7f0ba6a522c0)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7f0ba6a51ac0))(0x7f0ba6a59630)]), |
| filter(nil) |
| columns([{tbl1: ({tbl1: (tbl1.__pk_increment(0x7f0ba6a51d80), tbl1.col1(0x7f0ba6a30a90), tbl1.col2(0x7f0ba6a30d50))})}]), partitions(p0), |
| column_values([T_HIDDEN_PK(0x7f0ba6a52040)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7f0ba6a51800))(0x7f0ba6a522c0)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7f0ba6a51ac0))(0x7f0ba6a59630)]) |
| 4 - output([column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7f0ba6a51800))(0x7f0ba6a522c0)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7f0ba6a51ac0))(0x7f0ba6a59630)], |
| [T_HIDDEN_PK(0x7f0ba6a52040)]), filter(nil), rowset=256 |
| 5 - output([column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7f0ba6a51800))(0x7f0ba6a522c0)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7f0ba6a51ac0))(0x7f0ba6a59630)], |
| [T_HIDDEN_PK(0x7f0ba6a52040)]), filter(nil), rowset=256 |
| dop=16 |
| 6 - output([column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7f0ba6a51800))(0x7f0ba6a522c0)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7f0ba6a51ac0))(0x7f0ba6a59630)]), |
| filter(nil), rowset=256 |
| 7 - output([ANONYMOUS_VIEW1.col1(0x7f0ba6a51800)], [ANONYMOUS_VIEW1.col3(0x7f0ba6a51ac0)]), filter(nil), rowset=256 |
| access([ANONYMOUS_VIEW1.col1(0x7f0ba6a51800)], [ANONYMOUS_VIEW1.col3(0x7f0ba6a51ac0)]) |
| 8 - output([t2.col1(0x7f0ba6a50d40)], [t2.col3(0x7f0ba6a512f0)]), filter(nil), rowset=256 |
| 9 - output([t2.col1(0x7f0ba6a50d40)], [t2.col3(0x7f0ba6a512f0)]), filter(nil), rowset=256 |
| access([t2.col1(0x7f0ba6a50d40)], [t2.col3(0x7f0ba6a512f0)]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t2.__pk_increment(0x7f0ba6a6ccf0)]), range(MIN ; MAX)always true |
| Used Hint: |
| ------------------------------------- |
| /*+ |
| |
| USE_PLAN_CACHE( NONE ) |
| PARALLEL(16) |
| ENABLE_PARALLEL_DML |
| APPEND |
| APPEND |
| */ |
| Qb name trace: |
| ------------------------------------- |
| stmt_id:0, stmt_type:T_EXPLAIN |
| stmt_id:1, INS$1 |
| stmt_id:2, SEL$1 |
| Outline Data: |
| ------------------------------------- |
| /*+ |
| BEGIN_OUTLINE_DATA |
| FULL(@"SEL$1" "test"."t2"@"SEL$1") |
| USE_PLAN_CACHE( NONE ) |
| PARALLEL(16) |
| ENABLE_PARALLEL_DML |
| OPTIMIZER_FEATURES_ENABLE('4.0.0.0') |
| APPEND |
| APPEND |
| END_OUTLINE_DATA |
| */ |
| Optimization Info: |
| ------------------------------------- |
| t2: |
| table_rows:3 |
| physical_range_rows:3 |
| logical_range_rows:3 |
| index_back_rows:0 |
| output_rows:3 |
| est_method:local_storage |
| optimization_method:cost_based |
| avaiable_index_name:[tbl2] |
| table_id:500004:estimation info:(table_type:12, version:-1--1--1, logical_rc:3, physical_rc:3)] |
| stats version:0 |
| Plan Type: |
| DISTRIBUTED |
| Note: |
| Degree of Parallelism is 16 because of hint |
| Direct-mode is enabled in insert into select |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
86 rows in set
增量旁路导入
使用限制
- 有索引(不包括主键)的表不支持增量旁路导入。
- 有外键的表不支持增量旁路导入。
注意事项
增量旁路导入的数据会触发转储,对于数据量较小且能在分钟内完成导入的情况,不建议使用增量旁路导入。
语法
INSERT /*+ [APPEND | direct(need_sort,max_error,{'inc'|'inc_replace'})] enable_parallel_dml parallel(N) */ INTO table_name select_sentence
更多 INSERT INTO 语法的信息,请参见 INSERT(MySQL 模式) 和 INSERT(Oracle 模式)。
参数解释:
| 参数 | 描述 |
|---|---|
| APPEND | direct() | 使用 Hint 启用旁路导入功能。
|
| enable_parallel_dml parallel(N) | 加载数据的并行度。
说明一般情况下, |
| parallel(N) | 加载数据的并行度,必填项,取值是大于 1 的整数。 |
示例
INSERT INTO SELECT 语句中增量旁路导入的操作步骤与全量旁路导入的步骤一样,只需要将 full 字段的取值替换为 inc 或 inc_replace 即可。
obclient [test]> INSERT /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(2) */ INTO tbl2 SELECT * FROM tbl1;
返回结果如下:
Query OK, 8 rows affected
Records: 8 Duplicates: 0 Warnings: 0