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 1CREATE 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 SELECTINSERT INTO SELECT一般用于将查询结果保存到目标表中。SQL 1INSERT INTO target_table SELECT ... FROM source_table;其中
SELECT语句同一般的SELECT查询语句,可以包含WHERE JOIN等操作。 -
INSERT INTO VALUESINSERT 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 1INSERT 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 获取更多帮助信息。