4.1.2.4 Insert Into¶
INSERT INTO
支持将 Doris
查询的结果导入到另一个表中。 INSERT INTO
是一个同步导入方式,执行导入后返回导入结果。可以通过请求的返回判断导入是否成功。 INSERT INTO
可以保证导入任务的原子性,要么全部导入成功,要么全部导入失败。
主要的 Insert Into
命令包含以下两种:
-
INSERT INTO tbl SELECT ...
-
INSERT INTO tbl (col1, col2, ...) VALUES (1, 2, ...), (1,3, ...)
1 使用场景¶
-
用户希望仅导入几条假数据,验证一下
Doris
系统的功能。此时适合使用INSERT INTO VALUES
的语法,语法和MySQL
一样。不建议在生产环境中使用INSERT INTO VALUES
。 -
用户希望将已经在
Doris
表中的数据进行ETL
转换并导入到一个新的Doris
表中,此时适合使用INSERT INTO SELECT
语法。 -
与
Multi-Catalog
外部表机制进行配合,如通过Multi-Catalog
映射MySQL
或者Hive
系统中的表,然后通过INSERT INTO SELECT
语法将外部表中的数据导入到Doris
表中存储。 -
通过
Table Value Function(TVF)
功能,可以直接将对象存储或HDFS
上的文件作为Table
进行查询,并且支持自动的列类型推断。然后,通过INSERT INTO SELECT
语法将外部表中的数据导入到Doris
表中存储。
2 基本原理¶
在使用 INSERT INTO
时,需要通过 MySQL
协议发起导入作业给 FE
节点, FE
会生成执行计划,执行计划中前部是查询相关的算子,最后一个是 OlapTableSink
算子,用于将查询结果写到目标表中。执行计划会被发送给 BE
节点执行, Doris
会选定一个节点做为 Coordinator
节点, Coordinator
节点负责接受数据并分发数据到其他节点上。
3 快速上手¶
INSERT INTO
通过 MySQL
协议提交和传输。下例以 MySQL
命令行为例,演示通过 INSERT INTO
提交导入作业。
详细语法可以参见 INSERT INTO
。
3.1 前置检查¶
INSERT INTO
需要对目标表的 INSERT
权限。如果没有 INSERT
权限,可以通过 GRANT
命令给用户授权。
3.2 创建导入作业¶
3.2.1 INSERT INTO VALUES¶
-
创建源表
SQL 1 2 3 4 5 6 7
CREATE TABLE testdb.test_table( user_id BIGINT NOT NULL COMMENT "user id", name VARCHAR(20) COMMENT "name", age INT COMMENT "age" ) DUPLICATE KEY(user_id) DISTRIBUTED BY HASH(user_id) BUCKETS 10;
-
使用
INSERT INTO VALUES
向源表导入数据(不推荐在生产环境中使用)SQL 1 2 3 4 5 6
INSERT INTO testdb.test_table (user_id, name, age) VALUES (1, "Emily", 25), (2, "Benjamin", 35), (3, "Olivia", 28), (4, "Alexander", 60), (5, "Ava", 17);
INSERT INTO
是一种同步导入方式,导入结果会直接返回给用户。可以打开group commit
达到更高的性能。SQL 1 2
Query OK, 5 rows affected (0.308 sec) {'label':'label_3e52da787aab4222_9126d2fce8f6d1e5', 'status':'VISIBLE', 'txnId':'9081'}
-
查看导入数据
SQL 1 2 3 4 5 6 7
MySQL> SELECT COUNT(*) FROM testdb.test_table; +----------+ | count(*) | +----------+ | 5 | +----------+ 1 row in set (0.179 sec)
3.2.2 INSERT INTO SELECT¶
-
在上述操作的基础上,创建一个新表作为目标表(其
schema
与源表相同)SQL 1
CREATE TABLE testdb.test_table2 LIKE testdb.test_table;
-
使用
INSERT INTO SELECT
导入到新表SQL 1 2 3 4
INSERT INTO testdb.test_table2 SELECT * FROM testdb.test_table WHERE age < 30; Query OK, 3 rows affected (0.544 sec) {'label':'label_9c2bae970023407d_b2c5b78b368e78a7', 'status':'VISIBLE', 'txnId':'9084'}
-
查看导入数据
SQL 1 2 3 4 5 6 7
MySQL> SELECT COUNT(*) FROM testdb.test_table2; +----------+ | count(*) | +----------+ | 3 | +----------+ 1 row in set (0.071 sec)
-
可以使用
JOB
异步执行INSERT
。 -
数据源可以是
tvf
或者catalog
中的表。
3.3 查看导入作业¶
可以通过 show load
命令查看已完成的 INSERT INTO
任务。
SQL | |
---|---|
1 2 3 4 5 6 7 |
|
3.4 取消导入作业¶
用户可以通过 Ctrl-C
取消当前正在执行的 INSERT INTO
作业。
4 参考手册¶
4.1 导入命令¶
INSERT INTO
导入语法如下:
-
INSERT INTO SELECT
INSERT INTO SELECT
一般用于将查询结果保存到目标表中。SQL 1
INSERT INTO target_table SELECT ... FROM source_table;
其中
SELECT
语句同一般的SELECT
查询语句,可以包含WHERE JOIN
等操作。 -
INSERT INTO VALUES
INSERT INTO VALUES
一般仅用于Demo
,不建议在生产环境使用。SQL 1 2
INSERT INTO target_table (col1, col2, ...) VALUES (val1, val2, ...), (val3, val4, ...), ...;
4.2 导入配置参数¶
4.2.1 FE 配置¶
insert_load_default_timeout_second
-
默认值:
14400
(4
小时) -
参数描述:导入任务的超时时间,单位:秒。导入任务在该超时时间内未完成则会被系统取消,变成
CANCELLED
。
4.2.2 环境变量¶
insert_timeout
-
默认值:
14400
(4
小时) -
参数描述:
INSERT INTO
作为SQL
语句的的超时时间,单位:秒。
enable_insert_strict
-
默认值:
true
-
参数描述:如果设置为
true
,当INSERT INTO
遇到不合格数据时导入会失败。如果设置为false
,INSERT INTO
会忽略不合格的行,只要有一条数据被正确导入,导入就会成功。 -
解释:
INSERT INTO
无法控制错误率,只能通过该参数设置为严格检查数据质量或完全忽略错误数据。常见的数据不合格的原因有:源数据列长度超过目的数据列长度、列类型不匹配、分区不匹配、列顺序不匹配等。
insert_max_filter_ratio
-
默认值:
1.0
-
参数描述:自
2.1.5
版本。仅当enable_insert_strict
值为false
时生效。用于控制当使用INSERT INTO FROM S3/HDFS/LOCAL()
时,设定错误容忍率的。默认为1.0
表示容忍所有错误。可以取值0 ~ 1
之间的小数。表示当错误行数超过该比例后,INSERT
任务会失败。
enable_nereids_dml_with_pipeline
- 设置为
true
后,insert into
语句将尝试通过Pipeline
引擎执行。详见导入文档。
4.2.3 导入返回值¶
INSERT INTO
是一个 SQL
语句,其返回结果会根据查询结果的不同,分为以下几种:
结果集为空
如果 INSERT INTO
中的 SELECT
语句的查询结果集为空,则返回如下:
SQL | |
---|---|
1 2 |
|
Query OK
表示执行成功。 0 rows affected
表示没有数据被导入。
结果集不为空且 INSERT
执行成功
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Query OK
表示执行成功。 4 rows affected
表示总共有 4
行数据被导入。 2 warnings
表示被过滤的行数。
同时会返回一个 JSON
串:
JSON | |
---|---|
1 2 3 |
|
其中,返回结果参数如下表说明:
参数名称 | 说明 |
---|---|
TxnId | 导入事务的 ID |
Label | 导入作业的 label,通过 INSERT INTO tbl WITH LABEL label ... 指定 |
Status | 表示导入数据是否可见。如果可见,显示 visible,如果不可见,显示 committed - visible:表示导入成功,数据可见 - committed:该状态也表示导入已经完成,只是数据可能会延迟可见,无需重试 - Label Already Exists:Label 重复,需要更换 label - Fail:导入失败 |
Err | 导入错误信息 |
当需要查看被过滤的行时,用户可以通过 SHOW LOAD
语句
SQL | |
---|---|
1 |
|
返回结果中的 URL
可以用于查询错误的数据,具体见后面查看错误行小结。
数据不可见是一个临时状态,这批数据最终是一定可见的
可以通过 SHOW TRANSACTION
语句查看这批数据的可见状态:
SQL | |
---|---|
1 |
|
返回结果中的 TransactionStatus
列如果为 visible
,则表述数据可见。
JSON | |
---|---|
1 2 3 |
|
结果集不为空但 INSERT
执行失败
执行失败表示没有任何数据被成功导入,并返回如下:
SQL | |
---|---|
1 2 |
|
其中 ERROR 1064 (HY000): all partitions have no load data
显示失败原因。后面的 url
可以用于查询错误的数据,具体见后面查看错误行小结。
5 导入最佳实践¶
5.1 数据量¶
INSERT INTO
对数据量没有限制,大数据量导入也可以支持。但如果导入数据量过大,就需要通过以下配置修改系统的 INSERT INTO
导入超时时间,确保 导入超时 >= 数据量 / 预估导入速度
。
-
FE
配置参数insert_load_default_timeout_second
。 -
环境变量
insert_timeout
。
5.2 查看错误行¶
当 INSERT INTO
返回结果中提供了 url
字段时,可以通过以下命令查看错误行:
SQL | |
---|---|
1 |
|
示例:
SQL | |
---|---|
1 |
|
常见的错误的原因有:源数据列长度超过目的数据列长度、列类型不匹配、分区不匹配、列顺序不匹配等。
可以通过环境变量 enable_insert_strict
来控制 INSERT INTO
是否忽略错误行。
6 通过外部表 Multi-Catalog 导入数据¶
Doris
可以创建外部表。创建完成后,可以通过 INSERT INTO SELECT
的方式导入外部表的数据,当然也可以通过 SELECT
语句直接查询外部表的数据,
Doris
通过多源数据目录( Multi-Catalog
)功能,支持了包括 Apache Hive
、 Apache Iceberg
、 Apache Hudi
、 Apache Paimon(Incubating)
、 Elasticsearch
、 MySQL
、 Oracle
、 SQL Server
等主流数据湖、数据库的连接访问。
Multi-Catalog
相关功能,请查看湖仓一体文档。
这里以通过构建 Hive
外部表,导入其数据到 Doris
内部表来举例说明。
6.1 创建 Hive Catalog¶
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
6.2 导入数据¶
-
创建一张
Doris
的导入目标表SQL 1 2 3 4 5 6 7 8 9 10 11 12
CREATE TABLE `target_tbl` ( `k1` decimal(9, 3) NOT NULL COMMENT "", `k2` char(10) NOT NULL COMMENT "", `k3` datetime NOT NULL COMMENT "", `k5` varchar(20) NOT NULL COMMENT "", `k6` double NOT NULL COMMENT "" ) COMMENT "Doris Table" DISTRIBUTED BY HASH(k1) BUCKETS 2 PROPERTIES ( "replication_num" = "1" );
-
关于创建
Doris
表的详细说明,请参阅CREATE-TABLE
语法帮助。 -
导入数据(从
hive.db1.source_tbl
表导入到target_tbl
表)SQL 1
INSERT INTO target_tbl SELECT k1,k2,k3 FROM hive.db1.source_tbl limit 100;
INSERT
命令是同步命令,返回成功,即表示导入成功。
Warning
必须保证外部数据源与 Doris
集群是可以互通,包括 BE
节点和外部数据源的网络是互通的。
7 通过 TVF 导入数据¶
通过 Table Value Function
功能, Doris
可以直接将对象存储或 HDFS
上的文件作为 Table
进行查询分析、并且支持自动的列类型推断。详细介绍,请参考 湖仓一体/TVF
文档。
7.1 自动推断文件列类型¶
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
这里给出了了一个 s3 TVF
的例子。这个例子中指定了文件的路径、连接信息、认证信息等。
之后,通过 DESC FUNCTION
语法可以查看这个文件的 Schema
。
可以看到,对于 Parquet
文件, Doris
会根据文件内的元信息自动推断列类型。
目前支持对 Parquet
、 ORC
、 CSV
、 Json
格式进行分析和列类型推断。
配合 INSERT INTO SELECT
语法,可以方便将文件导入到 Doris
表中进行更快速的分析:
-
创建
doris
内部表SQL 1 2 3 4 5 6 7 8
CREATE TABLE IF NOT EXISTS test_table ( id int, name varchar(50), age int ) DISTRIBUTED BY HASH(id) BUCKETS 4 PROPERTIES("replication_num" = "1");
-
使用
S3 Table Value Function
插入数据SQL 1 2 3 4 5 6 7 8
INSERT INTO test_table (id,name,age) SELECT cast(id as INT) as id, name, cast (age as INT) as age FROM s3( "uri" = "<http://127.0.0.1:9312/test2/test.snappy.parquet>", "s3.access_key"= "ak", "s3.secret_key" = "sk", "format" = "parquet", "use_path_style" = "true");
Warning
-
如果
S3 / hdfs TVF
指定的uri
匹配不到文件,或者匹配到的所有文件都是空文件,那么S3 / hdfs TVF
将会返回空结果集。在这种情况下使用DESC FUNCTION
查看这个文件的Schema
,会得到一列虚假的列__dummy_col
,可忽略这一列。 -
如果指定
TVF
的format
为CSV The first line is empty, can not parse column numbers
,这因为无法通过该文件的第一行解析出Schema
。
8 更多帮助¶
关于 Insert Into
使用的更多详细语法,请参阅 INSERT INTO
命令手册,也可以在 MySQL
客户端命令行下输入 HELP INSERT
获取更多帮助信息。