首批通过分布式安全可靠测评,为关键业务系统打造
全量旁路导入
更新时间:2026-03-09 09:47:34
本文介绍如何通过 LOAD DATA 语句、INSERT INTO SELECT 语句和 CREATE TABLE AS SELECT 语句实现全量旁路导入。
注意事项
在使用全量旁路导入时,有以下注意事项:
OceanBase 数据库从 V4.3.0 版本开始支持 LOB 数据类型的旁路导入。
旁路导入期间会加表锁,表无法被写入其他数据,整个过程中表是只读的。
全量旁路导入适用于大表首次导入、10 GB~TB 级别的数据迁移以及 CPU 和内存都不是特别充裕的场景,因为旁路导入的执行路径短,可以省 CPU 开销。
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 分区,支持分区级旁路导入。
- 当 Session 级变量 foreign_key_checks 取值为 False 时,旁路导入操作不会进行外键约束校验。
LOAD DATA语句对于带唯一索引的全量旁路导入,当出现重复唯一索引键时,暂时不支持REPLACE或IGNORE关键字,也不支持设置容错行。
使用 LOAD DATA 语句旁路导入数据
LOAD DATA 语句通过使用 append/direct() Hint 来执行旁路导入,在未指定 Hint 时能基于配置项 default_load_mode 确定导入数据的行为。
注意
OceanBase 数据库通过并行处理技术优化 LOAD DATA 的数据导入速率。该操作将数据分成多个子任务并行执行,每个子任务都视为独立的事务,执行顺序是不固定的。因此对于没有主键的表,数据写入顺序可能与原文件中的顺序不同。
使用限制
- 在导入过程中无法同时执行两个写操作语句(即不能同时写一个表),因为导入过程中会先加表锁,并且整个导入过程中只能进行读操作。
- 不支持在触发器(Trigger)使用。
- 不支持含有生成列的表(某些索引会产生隐藏生成列,例如 KEY
idx_c2(c2(16)) GLOBAL)。 - 不支持单行超过 2M 的数据导入。
- 不支持 Liboblog 和闪回查询(Flashback Query)。
使用语法
LOAD DATA /*+ [APPEND | DIRECT(need_sort,max_error,'full')] parallel(N) */ [REMOTE_OSS | LOCAL] INFILE 'file_name' INTO TABLE table_name [PARTITION(PARTITION_OPTION)] [COMPRESSION]...
更多 LOAD DATA 语法的信息,请参见 LOAD DATA。
参数解释:
| 参数 | 描述 |
|---|---|
| APPEND | DIRECT() | 使用 Hint 启用旁路导入功能。
|
| parallel(N) | 必填项,加载数据的并行度,默认为 4。 |
| REMOTE_OSS | LOCAL | 可选项,
|
| file_name | 指定输入文件的路径和文件名。该参数格式与 REMOTE_OSS | LOCAL 的类型相互对应:
说明在导入 OSS 上的文件时,需要确保以下信息:
|
| table_name | 导入数据的表的名称,支持指定表任意列数目。 |
| PARTITION_OPTION | 指定分区旁路导入时的分区名:
|
| COMPRESSION | 指定压缩文件格式,取值有
|
使用示例
说明
下面的示例是从服务器端文件导入数据的方法。OceanBase 数据库 LOAD DATA 语句旁路导入数据还支持加载本地文件(LOCAL INFILE)的方式。更多有关 LOAD DATA LOCAL INFILE 的示例信息,请参见 使用 LOAD DATA 语句导入数据
登录到需要连接 OBServer 节点所在的机器上,在
/home/admin目录下创建测试数据。说明
OceanBase 数据库中的
LOAD DATA语句仅支持加载 OBServer 节点本地的输入文件。因此,需要在导入之前将文件拷贝到某台 OBServer 上。进入 OBServer 节点所在的机器。
[xxx@xxx /home/admin]# ssh admin@10.10.10.1创建测试数据
tbl1.csv。[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语句导入数据。创建表
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 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查询表
tbl2是否有数据,此时显示表为空。obclient [test]> SELECT * FROM tbl2; Empty set使用旁路导入将
tbl1.csv文件中的数据导入到表tbl2。指定表
tbl2的所有列导入数据。obclient [test]> LOAD DATA /*+ direct(true,1024,'full') 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,'full') 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,'full') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0, p1) FIELDS TERMINATED BY ',';指定表
tbl2的二级分区导入数据。obclient [test]> LOAD DATA /*+ direct(true,1024,'full') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0sp0_1, p1sp1_1) FIELDS TERMINATED BY ',';使用配置项
default_load_mode导入数据。设置
default_load_mode的值为FULL_DIRECT_WRITE。obclient [test]> ALTER SYSTEM SET default_load_mode ='FULL_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中已导入数据。
登录到需要连接 OBServer 节点所在的机器上,在
/home/admin目录下创建测试数据tbl1。说明
OceanBase 数据库中的
LOAD DATA语句仅支持加载 OBServer 节点本地的输入文件。因此,需要在导入之前将文件拷贝到某台 OBServer 上。进入 OBServer 节点所在的机器。
[xxx@xxx /home/admin]# ssh admin@10.10.10.1创建测试数据
tbl1.csv。[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 [SYS]> CREATE TABLE tbl2 ( 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查询表
tbl2是否有数据,此时显示表为空。obclient [SYS]> SELECT * FROM tbl2; Empty set使用旁路导入将
tbl1.csv文件中的数据导入到表tbl2。指定表
tbl2的所有列导入数据。obclient [SYS]> LOAD DATA /*+ direct(true,1024,'full') 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 [SYS]> LOAD DATA /*+ direct(true,1024,'full') 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 [SYS]> LOAD DATA /*+ direct(true,1024,'full') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0, p1) FIELDS TERMINATED BY ',';(可选)指定表
tbl2的二级分区导入数据。obclient [SYS]> LOAD DATA /*+ direct(true,1024,'full') parallel(16) */ INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 partition(p0sp0_1, p1sp1_1) FIELDS TERMINATED BY ',';使用配置项
default_load_mode导入数据。设置
default_load_mode的值为FULL_DIRECT_WRITE。obclient [SYS]> ALTER SYSTEM SET default_load_mode ='FULL_DIRECT_WRITE';不指定
LOAD DATA语句的 Hint。obclient [SYS]> LOAD DATA INFILE '/home/admin/tbl1.csv' INTO TABLE tbl2 FIELDS TERMINATED BY ',';
验证表
tbl2中是否已导入数据。obclient [SYS]> SELECT * FROM tbl2;查询结果如下:
+------+------+ | col1 | col2 | +------+------+ | 1 | 11 | | 2 | 22 | | 3 | 33 | +------+------+ 3 rows in set结果显示表
tbl2中已导入数据。
使用 INSERT INTO SELECT 语句旁路导入数据
INSERT INTO SELECT 语句通过 Hint 使用 append/direct() 加上 enable_parallel_dml 来执行旁路导入,在未指定 Hint 时能基于配置项 default_load_mode 确定导入数据的行为。
使用限制
- 只支持 PDML(Parallel Data Manipulation Language,并行数据操纵语言),非 PDML 不能用旁路导入。有关并行 DML 的更多信息,参见 并行 DML。
- 在导入过程中无法同时执行两个写操作语句(即不能同时写一个表),因为导入过程中会先加表锁,并且整个导入过程中只能进行读操作。
- 旁路导入属于 DDL 语句,无法在多行事务(包含多个操作的事务)中执行。
- 不能在 Begin 中执行。
- Autocommit 必须设置为 1。
- 不支持在触发器(Trigger)使用。
- 不支持含有生成列的表(某些索引会产生隐藏生成列,例如 KEY
idx_c2(c2(16)) GLOBAL)。 - 不支持 Liboblog 和闪回查询(Flashback Query)。
使用语法
INSERT /*+ [APPEND |DIRECT(need_sort,max_error,'full')] enable_parallel_dml parallel(N) */ INTO table_name [PARTITION(PARTITION_OPTION)] select_sentence
更多 INSERT INTO 语法的信息,请参见 INSERT(MySQL 模式) 和 INSERT(Oracle 模式)。
参数解释:
| 参数 | 描述 |
|---|---|
| APPEND | DIRECT() | 使用 Hint 启用旁路导入功能。
|
| enable_parallel_dml | 加载数据的并行度。
说明一般情况下, |
| parallel(N) | 加载数据的并行度,必填项,取值是大于 1 的整数。 |
| table_name | 导入数据的表的名称,支持指定表任意列数目。 |
| PARTITION_OPTION | 指定分区旁路导入时的分区名:
|
使用示例
示例 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, '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]> INSERT /*+ DIRECT(true, 0, 'full') 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, 'full') 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的值为FULL_DIRECT_WRITE。obclient [test]> ALTER SYSTEM SET default_load_mode ='FULL_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, '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 |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(0x7efa63627790), tbl1.col1(0x7efa63611980), tbl1.col3(0x7efa63611dc0))})}]), partitions(p0), | | column_values([T_HIDDEN_PK(0x7efa63627bd0)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.col1(0x7efa63626f10))(0x7efa63627ff0)], [column_conv(INT, | | PS:(11,0),NULL,ANONYMOUS_VIEW1.col3(0x7efa63627350))(0x7efa6362ff20)]) | | 3 - output([T_HIDDEN_PK(0x7efa63627bd0)], [ANONYMOUS_VIEW1.col1(0x7efa63626f10)], [ANONYMOUS_VIEW1.col3(0x7efa63627350)]), filter(nil), rowset=16 | | 4 - output([T_HIDDEN_PK(0x7efa63627bd0)], [ANONYMOUS_VIEW1.col1(0x7efa63626f10)], [ANONYMOUS_VIEW1.col3(0x7efa63627350)]), filter(nil), rowset=16 | | dop=16 | | 5 - output([ANONYMOUS_VIEW1.col1(0x7efa63626f10)], [ANONYMOUS_VIEW1.col3(0x7efa63627350)]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.col1(0x7efa63626f10)], [ANONYMOUS_VIEW1.col3(0x7efa63627350)]) | | 6 - output([t2.col1(0x7efa63625ed0)], [t2.col3(0x7efa63626780)]), filter(nil), rowset=16 | | 7 - output([t2.col1(0x7efa63625ed0)], [t2.col3(0x7efa63626780)]), filter(nil), rowset=16 | | access([t2.col1(0x7efa63625ed0)], [t2.col3(0x7efa63626780)]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([t2.__pk_increment(0x7efa63656410)]), range(MIN ; MAX)always true | | Used Hint: | | ------------------------------------- | | /*+ | | | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | DIRECT(TRUE, 0, 'FULL') | | */ | | 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, 'FULL') | | 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, 'full') 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, 'full') 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, 'full') 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, 'full') 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的值为FULL_DIRECT_WRITE。obclient [test]> ALTER SYSTEM SET default_load_mode ='FULL_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, 'full') enable_parallel_dml parallel(16) */ INTO tbl3 SELECT t2.col1,t2.col3 FROM tbl4 t2;返回结果如下:
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | =================================================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ----------------------------------------------------------------------------------- | | |0 |OPTIMIZER STATS MERGE | |3 |29 | | | |1 |└─PX COORDINATOR | |3 |29 | | | |2 | └─EXCHANGE OUT DISTR |:EX10001 |3 |27 | | | |3 | └─INSERT | |3 |27 | | | |4 | └─OPTIMIZER STATS GATHER | |3 |1 | | | |5 | └─EXCHANGE IN DISTR | |3 |1 | | | |6 | └─EXCHANGE OUT DISTR (RANDOM) |:EX10000 |3 |1 | | | |7 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|3 |1 | | | |8 | └─PX BLOCK ITERATOR | |3 |1 | | | |9 | └─COLUMN TABLE FULL SCAN|T2 |3 |1 | | | =================================================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output(nil), filter(nil), rowset=16 | | 1 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)]), filter(nil), rowset=16 | | 2 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)]), filter(nil), rowset=16 | | dop=16 | | 3 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)]), filter(nil) | | columns([{TBL3: ({TBL3: (TBL3.__pk_increment(0x7ef8f6027fa0), TBL3.COL1(0x7ef8f6011d50), TBL3.COL3(0x7ef8f6012190))})}]), partitions(p0), | | column_values([T_HIDDEN_PK(0x7ef8f60283e0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER, | | PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)]) | | 4 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL1(0x7ef8f6027720))(0x7ef8f60287f0)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60))(0x7ef8f6030710)], | | [T_HIDDEN_PK(0x7ef8f60283e0)]), filter(nil), rowset=16 | | 5 - output([T_HIDDEN_PK(0x7ef8f60283e0)], [ANONYMOUS_VIEW1.COL1(0x7ef8f6027720)], [ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60)]), filter(nil), rowset=16 | | 6 - output([T_HIDDEN_PK(0x7ef8f60283e0)], [ANONYMOUS_VIEW1.COL1(0x7ef8f6027720)], [ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60)]), filter(nil), rowset=16 | | dop=16 | | 7 - output([ANONYMOUS_VIEW1.COL1(0x7ef8f6027720)], [ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60)]), filter(nil), rowset=16 | | access([ANONYMOUS_VIEW1.COL1(0x7ef8f6027720)], [ANONYMOUS_VIEW1.COL3(0x7ef8f6027b60)]) | | 8 - output([T2.COL1(0x7ef8f60264c0)], [T2.COL3(0x7ef8f6026f90)]), filter(nil), rowset=16 | | 9 - output([T2.COL1(0x7ef8f60264c0)], [T2.COL3(0x7ef8f6026f90)]), filter(nil), rowset=16 | | access([T2.COL1(0x7ef8f60264c0)], [T2.COL3(0x7ef8f6026f90)]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([T2.__pk_increment(0x7ef8f60584a0)]), range(MIN ; MAX)always true | | Used Hint: | | ------------------------------------- | | /*+ | | | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | DIRECT(TRUE, 0, 'FULL') | | */ | | 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_COLUMN_TABLE(@"SEL$1" "T2"@"SEL$1") | | USE_PLAN_CACHE( NONE ) | | PARALLEL(16) | | ENABLE_PARALLEL_DML | | OPTIMIZER_FEATURES_ENABLE('4.3.3.0') | | DIRECT(TRUE, 0, 'FULL') | | 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 | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 82 rows in set (0.006 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, 'full') 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() Hint 来指定旁路导入的导数方式,在未指定 Hint 时能基于配置项 default_load_mode 确定导入数据的行为。
使用语法
CREATE /*+ [APPEND | DIRECT(need_sort,max_error,load_type)] parallel(N) */ TABLE table_name [AS] select_sentence
更多 CREATE TABLE 语法的信息,请参见 CREATE TABLE(MySQL 模式) 和 CREATE TABLE(Oracle 模式)。
参数解释:
| 参数 | 描述 |
|---|---|
| APPEND | DIRECT() | 使用 Hint 启用旁路导入功能。
|
| 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。使用
APPENDHint 旁路导入数据。obclient [test]> CREATE /*+ append parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;使用
DIRECTHint 旁路导入数据。obclient [test]> CREATE /*+ direct(true, 0, 'full') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;
不指定
CREATE TABLE AS SELECT语句的 Hint。设置配置项
default_load_mode的值为FULL_DIRECT_WRITE。obclient [test]> ALTER SYSTEM SET default_load_mode ='FULL_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。使用
APPENDHint 旁路导入数据。obclient [SYS]> CREATE /*+ append parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;使用
DIRECTHint 旁路导入数据。obclient [SYS]> CREATE /*+ direct(true, 0, 'full') parallel(4) */ TABLE tbl2 AS SELECT * FROM tbl1;
不指定
CREATE TABLE AS SELECT语句的 Hint。设置
default_load_mode的值为FULL_DIRECT_WRITE。obclient [SYS]> ALTER SYSTEM SET default_load_mode ='FULL_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中已导入数据。