首批通过分布式安全可靠测评,为关键业务系统打造
增量旁路导入
更新时间:2026-03-15 10:36:58
当表中已有数据,想要导入增量数据时,可选择增量旁路导入功能来完成。虽然通过全量旁路导入能够导入增量数据,但是通过全量旁路导入来导入增量数据的过程将重写所有的原始数据,导入性能不佳。增量旁路导入功能与全量旁路导入不同的是,导入流程将只会操作增量数据,能够保证导入性能。
本文介绍如何通过 LOAD DATA 语句、INSERT INTO SELECT 语句和 CREATE TABLE AS SELECT 语句实现增量旁路导入。
注意事项
在使用旁路导入时,有以下注意事项:
增量旁路导入的数据会触发转储,对于数据量较小且能在分钟内完成导入的情况,不建议使用增量旁路导入。
增量旁路导入支持目标表有非唯一局部索引。
LOAD DATA语句支持在多行事务中运行,在执行时会主动提交之前的事务。使用
INSERT INTO SELECT语句旁路导入数据时,只支持 PDML(Parallel Data Manipulation Language,并行数据操纵语言),非 PDML 不能用旁路导入。在
LOAD DATA语句和INSERT INTO SELECT语句中使用指定分区旁路导入时需要注意,目标表不能是复制表,且不能含有自增列、标识列、Global Index。对于 V4.3.5 版本,从 V4.3.5 BP1 版本开始增量旁路导入有以下变更:
- 如果目标表最后一级分区为 Hash/Key 分区,支持分区级旁路导入。
- 仅支持堆表加一个局部唯一索引的场景,如果目标表存在多个局部唯一索引或全局唯一索引,导入操作将失败。
LOAD DATA/INSERT INTO SELECT语句中,存在多个导入任务有重合分区时,不支持分区并行导入;无重合分区时,支持分区并行导入。- 当 Session 级变量 foreign_key_checks 取值为 False 时,旁路导入操作不会进行外键约束校验。
使用 LOAD DATA 语句旁路导入数据
LOAD DATA 语句通过使用 DIRECT() Hint 来执行增量旁路导入,在未指定 Hint 时能基于配置项 default_load_mode 确定导入数据的行为。
使用限制
- 在导入过程中无法同时执行两个写操作语句(即不能同时写一个表),因为导入过程中会先加表锁,并且整个导入过程中只能进行读操作。
- 不支持在触发器(Trigger)使用。
- 不支持含有生成列的表(某些索引会产生隐藏生成列,例如 KEY
idx_c2(c2(16)) GLOBAL)。 - 不支持单行超过 2M 的数据导入。
- 不支持 Liboblog 和闪回查询(Flashback Query)。
- 有外键的表不支持增量旁路导入。
使用语法
LOAD DATA /*+ [DIRECT(need_sort,max_error,{'inc'|'inc_replace'})] parallel(N) */ [REMOTE_OSS | LOCAL] INFILE 'file_name' INTO TABLE table_name [PARTITION(PARTITION_OPTION)] [COMPRESSION]...
更多 LOAD DATA 语法的信息,请参见 LOAD DATA。
参数解释:
| 参数 | 描述 |
|---|---|
| DIRECT() | 使用 Hint 启用旁路导入功能。DIRECT() 参数解释如下:
注意当 |
| parallel(N) | 必填项,加载数据的并行度,默认为 4。 |
| REMOTE_OSS | LOCAL | 可选项,
|
| file_name | 指定输入文件的路径和文件名。该参数格式与 REMOTE_OSS | LOCAL 的类型相互对应:
说明在导入 OSS 上的文件时,需要确保以下信息:
|
| table_name | 导入数据的表的名称,支持指定表任意列数目。 |
| PARTITION_OPTION | 指定分区旁路导入时的分区名:
|
| COMPRESSION | 指定压缩文件格式,取值有
|
说明
LOAD DATA 语句中增量旁路导入和全量旁路导入一样,也支持通配符方式多文件导入数据。但 LOAD DATA 语句的通配符只在 OBServer 本机生效(其他机器上登录 OBServer 使用 LOAD DATA 通配符不生效)。
使用示例
LOAD DATA 语句中增量旁路导入的操作步骤与全量旁路导入的步骤一样,只需要将 full 字段的取值替换为 inc 或 inc_replace 即可。
说明
下面的示例是从服务器端文件导入数据的方法。OceanBase 数据库 LOAD DATA 语句旁路导入数据还支持加载本地文件(LOCAL INFILE)的方式。更多有关 LOAD DATA LOCAL INFILE 的示例信息,请参见 使用 LOAD DATA 语句导入数据
登录到需要连接 OBServer 节点所在的机器上,在
/home/admin目录下创建测试数据tbl1。说明
OceanBase 数据库中的
LOAD DATA语句仅支持加载 OBServer 节点本地的输入文件。因此,需要在导入之前将文件拷贝到某台 OBServer 上。[xxx@xxx /home/admin]# ssh admin@10.10.10.1[admin@xxx /home/admin]# vi tbl1.csv 1,11 2,22 3,33设置导入的文件路径。
设置系统变量
secure_file_priv,配置导入或导出文件时可以访问的路径。注意
由于安全原因,设置系统变量
secure_file_priv时,只能通过本地 Unix Socket 连接数据库执行修改该全局变量的 SQL 语句。更多信息,请参见 secure_file_priv。登录到需要连接 OBServer 节点所在的机器上。
[xxx@xxx /home/admin]# ssh admin@10.10.10.1执行以下命令,通过本地 Unix Socket 连接方式连接租户
mysql001。obclient -S /home/admin/oceanbase/run/sql.sock -uroot@mysql001 -p******设置导入路径为
/home/admin。obclient [(none)]> SET GLOBAL secure_file_priv = "/home/admin"; Query OK, 0 rows affected
重新连接数据库后,使用
LOAD /*+ DIRECT */ DATA语句导入数据。创建表
tbl1。obclient [test]> CREATE TABLE tbl1 ( col1 INT PRIMARY KEY, col2 INT ) PARTITION BY RANGE (col1) SUBPARTITION BY RANGE (col1) ( PARTITION p0 VALUES LESS THAN (100) ( SUBPARTITION p0_1 VALUES LESS THAN (50), SUBPARTITION p0_2 VALUES LESS THAN (100) ), PARTITION p1 VALUES LESS THAN (200) ( SUBPARTITION p1_1 VALUES LESS THAN (150), SUBPARTITION p1_2 VALUES LESS THAN (200) ) ); Query OK, 0 rows affected查询表
tbl1是否有数据,此时显示表为空。obclient [test]> SELECT * FROM tbl1; Empty set使用旁路导入将
tbl1.csv文件中的数据导入到表tbl1。指定表
tbl1的所有列导入数据。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl1 FIELDS TERMINATED BY ','; Query OK, 3 rows affected Records: 3 Deleted: 0 Skipped: 0 Warnings: 0指定表
tbl1的指定任意列导入数据。例如指定col1,col2列。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl1 FIELDS TERMINATED BY ','(col1,col2); Query OK, 3 rows affected Records: 3 Deleted: 0 Skipped: 0 Warnings: 0(可选)指定表
tbl1的一级分区导入数据。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl1 partition(p0, p1) FIELDS TERMINATED BY ',';(可选)指定表
tbl1的二级分区导入数据。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl1 partition(p0sp0_1, p1sp1_1) FIELDS TERMINATED BY ',';使用配置项
default_load_mode导入数据。设置
default_load_mode的值为INC_DIRECT_WRITE或INC_REPLACE_DIRECT_WRITE。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';不指定
LOAD DATA语句的 Hint。obclient [test]> LOAD DATA INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ',';
验证表
tbl1中是否已导入数据。obclient [test]> SELECT * FROM tbl1;查询结果如下:
+------+------+ | col1 | col2 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set结果显示表
tbl2中已导入数据。
登录到需要连接 OBServer 节点所在的机器上,在
/home/admin目录下创建测试数据tbl1。说明
OceanBase 数据库中的
LOAD DATA语句仅支持加载 OBServer 节点本地的输入文件。因此,需要在导入之前将文件拷贝到某台 OBServer 上。[xxx@xxx /home/admin]# ssh admin@10.10.10.1[admin@xxx /home/admin]# vi tbl1.csv 1,11 2,22 3,33设置导入的文件路径。
设置系统变量
secure_file_priv,配置导入或导出文件时可以访问的路径。注意
由于安全原因,设置系统变量
secure_file_priv时,只能通过本地 Unix Socket 连接数据库执行修改该全局变量的 SQL 语句。更多信息,请参见 secure_file_priv。登录到需要连接 OBServer 节点所在的机器上。
[xxx@xxx /home/admin]# ssh admin@10.10.10.1执行以下命令,通过本地 Unix Socket 连接方式连接租户
oracle001。obclient -S /home/admin/oceanbase/run/sql.sock -usys@oracle001 -p******设置导入路径为
/home/admin。obclient [(none)]> SET GLOBAL secure_file_priv = "/home/admin"; Query OK, 0 rows affected
重新连接数据库后,使用
LOAD /*+ DIRECT */ DATA语句导入数据。创建表
tbl2。obclient [test]> CREATE TABLE tbl2 ( col1 INT PRIMARY KEY, col2 INT ) PARTITION BY RANGE (col1) SUBPARTITION BY RANGE (col1) ( PARTITION p0 VALUES LESS THAN (100) ( SUBPARTITION sp0_1 VALUES LESS THAN (50), SUBPARTITION sp0_2 VALUES LESS THAN (100) ), PARTITION p1 VALUES LESS THAN (200) ( SUBPARTITION sp1_1 VALUES LESS THAN (150), SUBPARTITION sp1_2 VALUES LESS THAN (200) ) ); Query OK, 0 rows affected查询表
tbl2是否有数据,此时显示表为空。obclient [test]> SELECT * FROM tbl2; Empty set使用旁路导入将
tbl1.csv文件中的数据导入到表tbl2。指定表
tbl2的所有列导入数据。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ','; Query OK, 3 rows affected Records: 3 Deleted: 0 Skipped: 0 Warnings: 0指定表
tbl2的指定任意列导入数据。例如指定col1,col2列。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ','(col1,col2); Query OK, 3 rows affected Records: 3 Deleted: 0 Skipped: 0 Warnings: 0(可选)指定表
tbl2的一级分区导入数据。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0, p1) FIELDS TERMINATED BY ',';(可选)指定表
tbl2的二级分区导入数据。obclient [test]> LOAD DATA /*+ direct(true,1024,'inc_replace') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0sp0_1, p1sp1_1) FIELDS TERMINATED BY ',';使用配置项
default_load_mode导入数据。设置
default_load_mode的值为INC_DIRECT_WRITE或INC_REPLACE_DIRECT_WRITE。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';不指定
LOAD DATA语句的 Hint。obclient [test]> LOAD DATA INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ',';
验证表
tbl2中是否已导入数据。obclient [test]> SELECT * FROM tbl2;查询结果如下:
+------+------+ | col1 | col2 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set结果显示表
tbl2中已导入数据。
使用 INSERT INTO SELECT 语句旁路导入数据
INSERT INTO SELECT 语句通过使用 direct() 加上 enable_parallel_dml Hint 来走旁路导入,在未指定 Hint 时能基于配置项 default_load_mode 确定导入数据的行为。
使用限制
- 只支持 PDML(Parallel Data Manipulation Language,并行数据操纵语言),非 PDML 不能用旁路导入。有关并行 DML 的更多信息,参见 并行 DML。
- 在导入过程中无法同时执行两个写操作语句(即不能同时写一个表),因为导入过程中会先加表锁,并且整个导入过程中只能进行读操作。
- 不支持在触发器(Trigger)使用。
- 不支持含有生成列的表(某些索引会产生隐藏生成列,例如 KEY
idx_c2(c2(16)) GLOBAL)。 - 不支持 Liboblog 和闪回查询(Flashback Query)。
- 有索引(不包括主键)的表不支持增量旁路导入。
- 有外键的表不支持增量旁路导入。
使用语法
INSERT /*+ [DIRECT(need_sort,max_error,{'inc'|'inc_replace'})] enable_parallel_dml parallel(N) */ INTO table_name [PARTITION(PARTITION_OPTION)] select_sentence
更多 INSERT INTO 语法的信息,请参见 INSERT(MySQL 模式) 和 INSERT(Oracle 模式)。
参数解释:
| 参数 | 描述 |
|---|---|
| DIRECT() | 使用 Hint 启用旁路导入功能。DIRECT() 参数解释如下:
|
| enable_parallel_dml | 加载数据的并行度。
说明一般情况下, |
| parallel(N) | 加载数据的并行度,必填项,取值是大于 1 的整数。 |
| table_name | 导入数据的表的名称,支持指定表任意列数目。 |
| PARTITION_OPTION | 指定分区旁路导入时的分区名:
|
使用示例
INSERT INTO SELECT 语句中增量旁路导入的操作步骤与全量旁路导入的步骤一样,只需要将 full 字段的取值替换为 inc 或 inc_replace 即可。
示例 1:使用 INSERT INTO SELECT 增量旁路导入的完整示例。
使用旁路导入将表 tbl2 中的部分数据导入到 tbl1 中。
查询表
tbl1是否有数据,此时显示表为空。obclient [test]> SELECT * FROM tbl1; Empty set查询表
tbl2是否有数据。obclient [test]> SELECT * FROM tbl2;查询到表
tbl2有数据。+------+------+------+ | col1 | col2 | col3 | +------+------+------+ | 1 | a1 | 11 | | 2 | a2 | 22 | | 3 | a3 | 33 | +------+------+------+ 3 rows in set使用旁路导入将表
tbl2中的数据导入到表tbl1。指定
INSERT INTO SELECT语句的 Hint。不指定分区导入。
obclient [test]> INSERT /*+ DIRECT(true, 0, 'inc_replace') 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]> INSERT /*+ DIRECT(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl1 partition(p0, p1) SELECT t2.col1,1 FROM tbl2 partition(p0, p1) t2; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0obclient [test]> INSERT /*+ DIRECT(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl1 partition(p0, p1) SELECT t2.col1,1 FROM tbl2 partition(p0sp0_1, p1sp1_1) t2; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0
不指定
INSERT INTO SELECT语句的 Hint。设置配置项
default_load_mode的值为INC_DIRECT_WRITE或INC_REPLACE_DIRECT_WRITE。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';obclient [test]> INSERT INTO tbl1 SELECT t2.col1,t2.col3 FROM tbl1 t2;
验证表
tbl1中是否已导入数据。obclient [test]> SELECT * FROM tbl1;查询结果如下:
+------+------+ | col1 | col2 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set结果显示表
tbl1中已导入数据。(可选)在
EXPLAIN EXTENDED语句的返回结果的Note中,查看是否通过旁路导入写入的数据。obclient [test]> EXPLAIN EXTENDED INSERT /*+ direct(true, 0, 'inc_replace') 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 |PX COORDINATOR | |3 |27 | | | |1 |└─EXCHANGE OUT DISTR |:EX10001 |3 |27 | | | |2 | └─INSERT | |3 |26 | | | |3 | └─EXCHANGE IN DISTR | |3 |1 | | | |4 | └─EXCHANGE OUT DISTR (RANDOM)|:EX10000 |3 |1 | | | |5 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|3 |1 | | | |6 | └─PX BLOCK ITERATOR | |3 |1 | | | |7 | └─TABLE FULL SCAN |t2 |3 |1 | | | ============================================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=16 | | 1 - output(nil), filter(nil), rowset=16 | | dop=16 | | 2 - output(nil), filter(nil) | | columns([{tbl1: ({tbl1: (tbl1.__pk_increment(0x7efa518277d0), tbl1.col1(0x7efa518119c0), tbl1.col3(0x7efa51811e00))})}]), partitions(p0), | | column_values([T_HIDDEN_PK(0x7efa51827c10)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7efa51826f50))(0x7efa51828030)], [column_conv(INT, | | PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7efa51827390))(0x7efa5182ff60)]) | | 3 - output([T_HIDDEN_PK(0x7efa51827c10)], [ANONYMOUS_VIEW1.col1(0x7efa51826f50)], [ANONYMOUS_VIEW1.col3(0x7efa51827390)]), filter(nil), rowset=16 | | 4 - output([T_HIDDEN_PK(0x7efa51827c10)], [ANONYMOUS_VIEW1.col1(0x7efa51826f50)], [ANONYMOUS_VIEW1.col3(0x7efa51827390)]), filter(nil), rowset=16 | | dop=16 | | 5 - output([ANONYMOUS_VIEW1.col1(0x7efa51826f50)], [ANONYMOUS_VIEW1.col3(0x7efa51827390)]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.col1(0x7efa51826f50)], [ANONYMOUS_VIEW1.col3(0x7efa51827390)]) | | 6 - output([t2.col1(0x7efa51825f10)], [t2.col3(0x7efa518267c0)]), filter(nil), rowset=16 | | 7 - output([t2.col1(0x7efa51825f10)], [t2.col3(0x7efa518267c0)]), filter(nil), rowset=16 | | access([t2.col1(0x7efa51825f10)], [t2.col3(0x7efa518267c0)]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([t2.__pk_increment(0x7efa51856410)]), range(MIN ; MAX)always true | | Used Hint: | | ------------------------------------- | | /*+ | | | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | DIRECT(TRUE, 0, 'INC_REPLACE') | | */ | | 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 | | PARALLEL(@"SEL$1" "t2"@"SEL$1" 16) | | FULL(@"SEL$1" "t2"@"SEL$1") | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | OPTIMIZER_FEATURES_ENABLE('4.3.3.0') | | DIRECT(TRUE, 0, 'INC_REPLACE') | | END_OUTLINE_DATA | | */ | | Optimization Info: | | ------------------------------------- | | t2: | | table_rows:3 | | physical_range_rows:3 | | logical_range_rows:3 | | index_back_rows:0 | | output_rows:3 | | table_dop:16 | | dop_method:Global DOP | | avaiable_index_name:[tbl2] | | stats info:[version=0, is_locked=0, is_expired=0] | | dynamic sampling level:0 | | estimation method:[DEFAULT, STORAGE] | | Plan Type: | | DISTRIBUTED | | Note: | | Degree of Parallelism is 16 because of hint | | Direct-mode is enabled in insert into select | +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ 77 rows in set (0.009 sec)
示例 2:对于 Range-Hash 二级分区表,指定一级分区旁路导入数据。
目标表为二级分区,一级为 Range 分区,二级为 Hash 分区,指定一级分区增量旁路导入。
创建包含两个分区的表
tbl1,一级为 Range 分区,二级为 Hash 分区。obclient [test]> CREATE TABLE tbl1(col1 INT,col2 INT) PARTITION BY RANGE COLUMNS(col1) SUBPARTITION BY HASH(col2) SUBPARTITIONS 3 ( PARTITION p0 VALUES LESS THAN(10), PARTITION p1 VALUES LESS THAN(20));使用旁路导入将表
tbl2中的数据导入到表tbl1的p0、p1分区中。obclient [test]> insert /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(3) append */ into tbl1 partition(p0,p1) select * from tbl2 where col1 <20;
示例 1:使用 INSERT INTO SELECT 增量旁路导入的完整示例。
使用旁路导入将表 tbl4 中的部分数据导入到 tbl3 中。
查询表
tbl3是否有数据,此时显示表为空。obclient [test]> SELECT * FROM tbl3; Empty set查询表
tbl4是否有数据。obclient [test]> SELECT * FROM tbl4;查询到表
tbl4有数据。+------+------+------+ | COL1 | COL2 | COL3 | +------+------+------+ | 1 | a1 | 11 | | 2 | a2 | 22 | | 3 | a3 | 33 | +------+------+------+ 3 rows in set (0.000 sec)使用旁路导入将表
tbl4中的数据导入到表tbl3。指定
INSERT INTO SELECT语句的 Hint。不指定分区导入。
obclient [test]> INSERT /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl3 SELECT t2.col1, t2.col3 FROM tbl4 t2 WHERE ROWNUM <= 10000; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0(可选)指定分区导入。
obclient [test]> INSERT /*+ DIRECT(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl3 partition(p0, p1) SELECT t2.col1,1 FROM tbl4 partition(p0, p1) t2; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0obclient [test]> INSERT /*+ DIRECT(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl3 partition(p0, p1) SELECT t2.col1,1 FROM tbl4 partition(p0sp0_1, p1sp1_1) t2; Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0
不指定
INSERT INTO SELECT语句的 Hint。设置配置项
default_load_mode的值为INC_DIRECT_WRITE或INC_REPLACE_DIRECT_WRITE。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';obclient [test]> INSERT INTO tbl3 SELECT t2.col1, t2.col3 FROM tbl4 t2 WHERE ROWNUM <= 10000;
验证表
tbl3中是否已导入数据。obclient [test]> SELECT * FROM tbl3;查询结果如下:
+------+------+ | col1 | col3 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set结果显示表
tbl3中已导入数据。(可选)在
EXPLAIN EXTENDED语句的返回结果的Note中,查看是否通过旁路导入写入的数据。obclient [test]> EXPLAIN EXTENDED INSERT /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(16) */ INTO tbl3 SELECT t2.col1,t2.col3 FROM tbl4 t2 WHERE ROWNUM <= 10000; 返回结果如下: ```shell +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ========================================================================================= | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ----------------------------------------------------------------------------------------- | | |0 |PX COORDINATOR | |3 |34 | | | |1 |└─EXCHANGE OUT DISTR |:EX10002 |3 |33 | | | |2 | └─INSERT | |3 |32 | | | |3 | └─EXCHANGE IN DISTR | |3 |7 | | | |4 | └─EXCHANGE OUT DISTR (RANDOM) |:EX10001 |3 |7 | | | |5 | └─MATERIAL | |3 |3 | | | |6 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|3 |3 | | | |7 | └─LIMIT | |3 |3 | | | |8 | └─EXCHANGE IN DISTR | |3 |3 | | | |9 | └─EXCHANGE OUT DISTR |:EX10000 |3 |1 | | | |10| └─LIMIT | |3 |1 | | | |11| └─PX BLOCK ITERATOR | |3 |1 | | | |12| └─COLUMN TABLE FULL SCAN|T2 |3 |1 | | | ========================================================================================= | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=16 | | 1 - output(nil), filter(nil), rowset=16 | | dop=16 | | 2 - output(nil), filter(nil) | | columns([{TBL3: ({TBL3: (TBL3.__pk_increment(0x7efaad22b0e0), TBL3.COL1(0x7efaad2123f0), TBL3.COL3(0x7efaad212830))})}]), partitions(p0), | | column_values([T_HIDDEN_PK(0x7efaad22b520)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7efaad22a860))(0x7efaad22b930)], [column_conv(NUMBER, | | PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7efaad22aca0))(0x7efaad233850)]) | | 3 - output([T_HIDDEN_PK(0x7efaad22b520)], [ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]), filter(nil), rowset=16 | | 4 - output([T_HIDDEN_PK(0x7efaad22b520)], [ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]), filter(nil), rowset=16 | | is_single, dop=1 | | 5 - output([ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]), filter(nil), rowset=16 | | 6 - output([ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.COL1(0x7efaad22a860)], [ANONYMOUS_VIEW1.COL3(0x7efaad22aca0)]) | | 7 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | limit(cast(FLOOR(cast(10000, NUMBER(-1, -85))(0x7efaad227ef0))(0x7efaad25ac30), BIGINT(-1, 0))(0x7efaad25b6d0)), offset(nil) | | 8 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | 9 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | dop=16 | | 10 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | limit(cast(FLOOR(cast(10000, NUMBER(-1, -85))(0x7efaad227ef0))(0x7efaad25ac30), BIGINT(-1, 0))(0x7efaad25b6d0)), offset(nil) | | 11 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | 12 - output([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), filter(nil), rowset=16 | | access([T2.COL1(0x7efaad229470)], [T2.COL3(0x7efaad229f40)]), partitions(p0) | | limit(cast(FLOOR(cast(10000, NUMBER(-1, -85))(0x7efaad227ef0))(0x7efaad25ac30), BIGINT(-1, 0))(0x7efaad25b6d0)), offset(nil), is_index_back=false, | | is_global_index=false, | | range_key([T2.__pk_increment(0x7efaad25a720)]), range(MIN ; MAX)always true | | Used Hint: | | ------------------------------------- | | /*+ | | | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | DIRECT(TRUE, 0, 'INC_REPLACE') | | */ | | Qb name trace: | | ------------------------------------- | | stmt_id:0, stmt_type:T_EXPLAIN | | stmt_id:1, INS$1 | | stmt_id:2, SEL$1 | | stmt_id:3, parent:SEL$1 > SEL$658037CB > SEL$DCAFFB86 | | Outline Data: | | ------------------------------------- | | /*+ | | BEGIN_OUTLINE_DATA | | PARALLEL(@"SEL$DCAFFB86" "T2"@"SEL$1" 16) | | FULL(@"SEL$DCAFFB86" "T2"@"SEL$1") | | USE_COLUMN_TABLE(@"SEL$DCAFFB86" "T2"@"SEL$1") | | MERGE(@"SEL$658037CB" < "SEL$1") | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | OPTIMIZER_FEATURES_ENABLE('4.3.3.0') | | DIRECT(TRUE, 0, 'INC_REPLACE') | | END_OUTLINE_DATA | | */ | | Optimization Info: | | ------------------------------------- | | T2: | | table_rows:3 | | physical_range_rows:3 | | logical_range_rows:3 | | index_back_rows:0 | | output_rows:3 | | table_dop:16 | | dop_method:Global DOP | | avaiable_index_name:[TBL4] | | stats info:[version=0, is_locked=0, is_expired=0] | | dynamic sampling level:0 | | estimation method:[DEFAULT, STORAGE] | | Plan Type: | | DISTRIBUTED | | Note: | | Degree of Parallelism is 16 because of hint | | Direct-mode is enabled in insert into select | | Expr Constraints: | | cast(FLOOR(cast(10000, NUMBER(-1, -85))), BIGINT(-1, 0)) >= 1 result is TRUE | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 96 rows in set (0.007 sec)
示例 2:对于 Range-Hash 二级分区表,指定一级分区旁路导入数据。
目标表为二级分区,一级为 Range 分区,二级为 Hash 分区,指定一级分区增量旁路导入。
创建包含两个分区的表
tbl1,一级为 Range 分区,二级为 Hash 分区。obclient [test]> CREATE TABLE tbl1_1 ( col1 INT, col2 INT ) PARTITION BY RANGE (col1) SUBPARTITION BY HASH (col2) SUBPARTITION TEMPLATE ( SUBPARTITION sp1, SUBPARTITION sp2, SUBPARTITION sp3 ) ( PARTITION p0 VALUES LESS THAN (10), PARTITION p1 VALUES LESS THAN (20) );使用旁路导入将表
tbl2中的数据导入到表tbl1的p0、p1分区中。obclient [test]> insert /*+ direct(true, 0, 'inc_replace') enable_parallel_dml parallel(3) append */ into tbl1 partition(p0,p1) select * from tbl2 where col1 <20;
使用 CREATE TABLE AS SELECT 语句旁路导入数据
CREATE TABLE AS SELECT 语句通过设置 DIRECT() 和 PARALLE() Hint 来指定旁路导入的导数方式,在未指定 Hint 时能基于配置项 default_load_mode 确定导入数据的行为。
使用语法
CREATE /*+ [DIRECT(need_sort,max_error,{'inc'|'inc_replace'})] parallel(N) */ TABLE table_name [AS] select_sentence
更多 CREATE TABLE AS SELECT 语法的信息,请参见 CREATE TABLE(MySQL 模式) 和 CREATE TABLE(Oracle 模式)。
参数解释:
| 参数 | 描述 |
|---|---|
| DIRECT() | 使用 Hint 启用旁路导入功能。DIRECT() 参数解释如下:
注意当 |
| parallel(N) | 加载数据的并行度,必填项,取值是大于 1 的整数。 |
使用示例
使用旁路导入将表 tbl1 中的数据导入到其他表中。
创建表
tbl1。obclient [test]> CREATE TABLE tbl1(c1 int);插入数据到表
tbl1。obclient [test]> INSERT INTO tbl1 VALUES (1),(2),(3);查询表
tbl1中的数据。obclient [test]> SELECT * FROM tbl1;查询结果如下:
+------+ | c1 | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.027 sec)使用旁路导入将表
tbl1中数据导入到表tbl2。指定
CREATE TABLE AS SELECT语句的 Hint。使用
incHint 旁路导入数据。obclient [test]> CREATE /*+ direct(true, 0, 'inc') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;使用
inc_replaceHint 旁路导入数据。obclient [test]> CREATE /*+ direct(true, 0, 'inc_replace') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;
不指定
CREATE TABLE AS SELECT语句的 Hint。设置配置项
default_load_mode的值为INC_DIRECT_WRITE或INC_REPLACE_DIRECT_WRITE。obclient [test]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';obclient [test]> CREATE TABLE tbl2 AS SELECT * FROM tbl1;
验证表
tbl2中是否已导入数据。obclient [test]> SELECT * FROM tbl2;查询结果如下:
+------+ | c1 | +------+ | 1 | | 3 | | 2 | +------+ 3 rows in set (0.050 sec)结果显示表
tbl2中已导入数据。
使用旁路导入将表 tbl1 中的数据导入到其他表中。
创建表
tbl1。obclient [SYS]> CREATE TABLE tbl1(c1 int);插入数据到表
tbl1。obclient [SYS]> INSERT INTO tbl1 VALUES (1),(2),(3);查询表
tbl1中的数据。obclient [SYS]> SELECT * FROM tbl1;查询结果如下:
+------+ | C1 | +------+ | 1 | | 2 | | 3 | +------+ 3 rows in set (0.045 sec)使用旁路导入将表
tbl1中数据导入到表tbl2。指定
CREATE TABLE AS SELECT语句的 Hint。使用
incHint 旁路导入数据。obclient [SYS]> CREATE /*+ direct(true, 0, 'inc') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;使用
inc_replaceHint 旁路导入数据。obclient [SYS]> CREATE /*+ direct(true, 0, 'inc_replace') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;
不指定
CREATE TABLE AS SELECT语句的 Hint。设置配置项
default_load_mode的值为INC_DIRECT_WRITE或INC_REPLACE_DIRECT_WRITE。obclient [SYS]> ALTER SYSTEM SET default_load_mode ='INC_DIRECT_WRITE';obclient [SYS]> CREATE TABLE tbl2 AS SELECT * FROM tbl1;
验证表
tbl2中是否已导入数据。obclient [SYS]> SELECT * FROM tbl2;查询结果如下:
+------+ | C1 | +------+ | 3 | | 2 | | 1 | +------+ 3 rows in set (0.013 sec)结果显示表
tbl2中已导入数据。