INSERT

Name

INSERT

Description

该语句是完成数据插入操作。

  1. INSERT INTO table_name
  2. [ PARTITION (p1, ...) ]
  3. [ WITH LABEL label]
  4. [ (column [, ...]) ]
  5. [ [ hint [, ...] ] ]
  6. { VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }

Parameters

tablet_name: 导入数据的目的表。可以是 db_name.table_name 形式

partitions: 指定待导入的分区,必须是 table_name 中存在的分区,多个分区名称用逗号分隔

label: 为 Insert 任务指定一个 label

column_name: 指定的目的列,必须是 table_name 中存在的列

expression: 需要赋值给某个列的对应表达式

DEFAULT: 让对应列使用默认值

query: 一个普通查询,查询的结果会写入到目标中

hint: 用于指示 INSERT 执行行为的一些指示符。streaming 和 默认的非 streaming 方式均会使用同步方式完成 INSERT 语句执行 非 streaming 方式在执行完成后会返回一个 label 方便用户通过 SHOW LOAD 查询导入的状态

注意:

当前执行 INSERT 语句时,对于有不符合目标表格式的数据,默认的行为是过滤,比如字符串超长等。但是对于有要求数据不能够被过滤的业务场景,可以通过设置会话变量 enable_insert_stricttrue 来确保当有数据被过滤掉的时候,INSERT 不会被执行成功。

Example

test 表包含两个列c1, c2

  1. test表中导入一行数据
  1. INSERT INTO test VALUES (1, 2);
  2. INSERT INTO test (c1, c2) VALUES (1, 2);
  3. INSERT INTO test (c1, c2) VALUES (1, DEFAULT);
  4. INSERT INTO test (c1) VALUES (1);

其中第一条、第二条语句是一样的效果。在不指定目标列时,使用表中的列顺序来作为默认的目标列。 第三条、第四条语句表达的意思是一样的,使用c2列的默认值,来完成数据导入。

  1. test表中一次性导入多行数据
  1. INSERT INTO test VALUES (1, 2), (3, 2 + 2);
  2. INSERT INTO test (c1, c2) VALUES (1, 2), (3, 2 * 2);
  3. INSERT INTO test (c1) VALUES (1), (3);
  4. INSERT INTO test (c1, c2) VALUES (1, DEFAULT), (3, DEFAULT);

其中第一条、第二条语句效果一样,向test表中一次性导入两条数据 第三条、第四条语句效果已知,使用c2列的默认值向test表中导入两条数据

  1. test 表中导入一个查询语句结果
  1. INSERT INTO test SELECT * FROM test2;
  2. INSERT INTO test (c1, c2) SELECT * from test2;
  1. test 表中导入一个查询语句结果,并指定 partition 和 label
  1. INSERT INTO test PARTITION(p1, p2) WITH LABEL `label1` SELECT * FROM test2;
  2. INSERT INTO test WITH LABEL `label1` (c1, c2) SELECT * from test2;

异步的导入其实是,一个同步的导入封装成了异步。填写 streaming 和不填写的执行效率是一样的。

由于Doris之前的导入方式都是异步导入方式,为了兼容旧有的使用习惯,不加 streaming 的 INSERT 语句依旧会返回一个 label,用户需要通过SHOW LOAD命令查看此label导入作业的状态。

Keywords

  1. INSERT

Best Practice

  1. 查看返回结果

    INSERT 操作是一个同步操作,返回结果即表示操作结束。用户需要根据返回结果的不同,进行对应的处理。

    1. 执行成功,结果集为空

      如果 insert 对应 select 语句的结果集为空,则返回如下:

  1. ```sql
  2. mysql> insert into tbl1 select * from empty_tbl;
  3. Query OK, 0 rows affected (0.02 sec)

Query OK 表示执行成功。0 rows affected 表示没有数据被导入。

  1. 2. 执行成功,结果集不为空
  2. 在结果集不为空的情况下。返回结果分为如下几种情况:
  3. 1. Insert 执行成功并可见:
  1. ```sql
  2. mysql> insert into tbl1 select * from tbl2;
  3. Query OK, 4 rows affected (0.38 sec)
  4. {'label':'insert_8510c568-9eda-4173-9e36-6adc7d35291c', 'status':'visible', 'txnId':'4005'}
  5. mysql> insert into tbl1 with label my_label1 select * from tbl2;
  6. Query OK, 4 rows affected (0.38 sec)
  7. {'label':'my_label1', 'status':'visible', 'txnId':'4005'}
  8. mysql> insert into tbl1 select * from tbl2;
  9. Query OK, 2 rows affected, 2 warnings (0.31 sec)
  10. {'label':'insert_f0747f0e-7a35-46e2-affa-13a235f4020d', 'status':'visible', 'txnId':'4005'}
  11. mysql> insert into tbl1 select * from tbl2;
  12. Query OK, 2 rows affected, 2 warnings (0.31 sec)
  13. {'label':'insert_f0747f0e-7a35-46e2-affa-13a235f4020d', 'status':'committed', 'txnId':'4005'}
  14. ```
  15. `Query OK` 表示执行成功。`4 rows affected` 表示总共有4行数据被导入。`2 warnings` 表示被过滤的行数。
  16. 同时会返回一个 json 串:
  17. ```json
  18. {'label':'my_label1', 'status':'visible', 'txnId':'4005'}
  19. {'label':'insert_f0747f0e-7a35-46e2-affa-13a235f4020d', 'status':'committed', 'txnId':'4005'}
  20. {'label':'my_label1', 'status':'visible', 'txnId':'4005', 'err':'some other error'}
  21. ```
  22. `label` 为用户指定的 label 或自动生成的 labelLabel 是该 Insert Into 导入作业的标识。每个导入作业,都有一个在单 database 内部唯一的 Label
  23. `status` 表示导入数据是否可见。如果可见,显示 `visible`,如果不可见,显示 `committed`
  24. `txnId` 为这个 insert 对应的导入事务的 id
  25. `err` 字段会显示一些其他非预期错误。
  26. 当需要查看被过滤的行时,用户可以通过如下语句
  27. ```sql
  28. show load where label="xxx";
  29. ```
  30. 返回结果中的 URL 可以用于查询错误的数据,具体见后面 **查看错误行** 小结。
  31. **数据不可见是一个临时状态,这批数据最终是一定可见的**
  32. 可以通过如下语句查看这批数据的可见状态:
  33. ```sql
  34. show transaction where id=4005;
  35. ```
  36. 返回结果中的 `TransactionStatus` 列如果为 `visible`,则表述数据可见。
  1. 3. 执行失败
  2. 执行失败表示没有任何数据被成功导入,并返回如下:
  1. mysql> insert into tbl1 select * from tbl2 where k1 = "a";
  2. ERROR 1064 (HY000): all partitions have no load data. url: http://10.74.167.16:8042/api/_load_error_log?file=__shard_2/error_log_insert_stmt_ba8bb9e158e4879-ae8de8507c0bf8a2_ba8bb9e158e4879_ae8de8507c0bf8a2

其中 ERROR 1064 (HY000): all partitions have no load data 显示失败原因。后面的 url 可以用于查询错误的数据:

  1. show load warnings on "url";

可以查看到具体错误行。 ```

  1. 超时时间

    INSERT 操作的超时时间由 会话变量 query_timeout 控制。默认为5分钟。超时则作业会被取消。

  2. Label 和原子性

    INSERT 操作同样能够保证导入的原子性,可以参阅 导入事务和原子性 文档。

    当需要使用 CTE(Common Table Expressions) 作为 insert 操作中的查询部分时,必须指定 WITH LABELcolumn 部分。

  3. 过滤阈值

    与其他导入方式不同,INSERT 操作不能指定过滤阈值(max_filter_ratio)。默认的过滤阈值为 1,即素有错误行都可以被忽略。

    对于有要求数据不能够被过滤的业务场景,可以通过设置 会话变量 enable_insert_stricttrue 来确保当有数据被过滤掉的时候,INSERT 不会被执行成功。

  4. 性能问题

    不见使用 VALUES 方式进行单行的插入。如果必须这样使用,请将多行数据合并到一个 INSERT 语句中进行批量提交。