INSERT 算子用于将指定的数据插入数据表,数据来源包括直接指定的值和子查询的结果。

OceanBase 数据库支持的 INSERT 算子包括 INSERT 和 MULTI PARTITION INSERT。

INSERT

INSERT 算子用于向数据表的单个分区中插入数据。

如下例所示,Q1 查询将值 (1, ‘100’) 插入到非分区表 t1 中。其中 1 号算子 EXPRESSION 用来生成常量表达式的值。

  1. obclient>CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 VARCHAR2(10));
  2. Query OK, 0 rows affected (0.12 sec)
  3. obclient>CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 VARCHAR2(10)) PARTITION BY
  4. HASH(c1) PARTITIONS 10;
  5. Query OK, 0 rows affected (0.12 sec)
  6. obclient>CREATE TABLE t3 (c1 INT PRIMARY KEY, c2 VARCHAR2(10));
  7. Query OK, 0 rows affected (0.12 sec)
  8. obclient>CREATE INDEX IDX_t3_c2 ON t3 (c2) PARTITION BY HASH(c2) PARTITIONS 3;
  9. Query OK, 0 rows affected (0.12 sec)
  10. Q1:
  11. obclient>EXPLAIN INSERT INTO t1 VALUES (1, '100')\G;
  12. *************************** 1. row ***************************
  13. Query Plan:
  14. ====================================
  15. |ID|OPERATOR |NAME|EST. ROWS|COST|
  16. ------------------------------------
  17. |0 |INSERT | |1 |1 |
  18. |1 | EXPRESSION| |1 |1 |
  19. ====================================
  20. Outputs & filters:
  21. -------------------------------------
  22. 0 - output([__values.C1], [__values.C2]), filter(nil),
  23. columns([{T1: ({T1: (T1.C1, T1.C2)})}]), partitions(p0)
  24. 1 - output([__values.C1], [__values.C2]), filter(nil)
  25. values({1, '100'})

上述示例中,执行计划展示中的 outputs & filters 详细列出了 INSERT 算子的输出信息如下:

信息名称

含义

output

该算子输出的表达式。

filter

该算子上的过滤条件。

由于示例中 INSERT 算子没有设置 filter,所以为 nil。

columns

插入操作涉及的数据表的列。

partitions

插入操作涉及到的数据表的分区(非分区表可以认为是一个只有一个分区的分区表)。

更多 INSERT 算子的示例如下:

  • Q2 查询将值(2, ‘200’)、(3, ‘300’)插入到表 t1 中。

    1. Q2:
    2. obclient>EXPLAIN INSERT INTO t1 VALUES (2, '200'),(3, '300')\G;
    3. *************************** 1. row ***************************
    4. Query Plan:
    5. ====================================
    6. |ID|OPERATOR |NAME|EST. ROWS|COST|
    7. ------------------------------------
    8. |0 |INSERT | |2 |1 |
    9. |1 | EXPRESSION| |2 |1 |
    10. ====================================
    11. Outputs & filters:
    12. -------------------------------------
    13. 0 - output([__values.C1], [__values.C2]), filter(nil),
    14. columns([{T1: ({T1: (T1.C1, T1.C2)})}]), partitions(p0)
    15. 1 - output([__values.C1], [__values.C2]), filter(nil)
    16. values({2, '200'}, {3, '300'})
  • Q3 查询将子查询 SELECT * FROM t3 的结果插入到表 t1 中。

    1. Q3:
    2. obclient>EXPLAIN INSERT INTO t1 SELECT * FROM t3\G;
    3. *************************** 1. row ***************************
    4. Query Plan:
    5. ====================================
    6. |0 |INSERT | |100000 |117862|
    7. |1 | EXCHANGE IN DISTR | |100000 |104060|
    8. |2 | EXCHANGE OUT DISTR| |100000 |75662 |
    9. |3 | SUBPLAN SCAN |VIEW1|100000 |75662 |
    10. |4 | TABLE SCAN |T3 |100000 |61860 |
    11. ================================================
    12. Outputs & filters:
    13. -------------------------------------
    14. 0 - output([VIEW1.C1], [VIEW1.C2]), filter(nil),
    15. columns([{T1: ({T1: (T1.C1, T1.C2)})}]), partitions(p0)
    16. 1 - output([VIEW1.C1], [VIEW1.C2]), filter(nil)
    17. 2 - output([VIEW1.C1], [VIEW1.C2]), filter(nil)
    18. 3 - output([VIEW1.C1], [VIEW1.C2]), filter(nil),
    19. access([VIEW1.C1], [VIEW1.C2])
    20. 4 - output([T3.C1], [T3.C2]), filter(nil),
    21. access([T3.C2], [T3.C1]), partitions(p0)
  • Q4 查询将值(1, ‘100’)插入到分区表 t2 中,通过 partitions 参数可以看出,该值会被插入到 t2 的 p5 分区。

    1. Q4:
    2. obclient>EXPLAIN INSERT INTO t2 VALUES (1, '100')\G;
    3. *************************** 1. row ***************************
    4. Query Plan:
    5. ====================================
    6. |ID|OPERATOR |NAME|EST. ROWS|COST|
    7. ------------------------------------
    8. |0 |INSERT | |1 |1 |
    9. |1 | EXPRESSION| |1 |1 |
    10. ====================================
    11. Outputs & filters:
    12. -------------------------------------
    13. 0 - output([__values.C1], [__values.C2]), filter(nil),
    14. columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p5)
    15. 1 - output([__values.C1], [__values.C2]), filter(nil)
    16. values({1, '100'})

MULTI PARTITION INSERT

MULTI PARTITION INSERT 算子用于向数据表的多个分区中插入数据。

如下例所示,Q5 查询将值(2, ‘200’)、(3, ‘300’)插入到分区表 t2 中,通过 partitions 可以看出,这些值会被插入到 t2 的 p0 和 p6 分区。

  1. Q5:
  2. obclient>EXPLAIN INSERT INTO t2 VALUES (2, '200'),(3, '300')\G;
  3. *************************** 1. row ***************************
  4. Query Plan:
  5. ===============================================
  6. |ID|OPERATOR |NAME|EST. ROWS|COST|
  7. -----------------------------------------------
  8. |0 |MULTI PARTITION INSERT| |2 |1 |
  9. |1 | EXPRESSION | |2 |1 |
  10. ===============================================
  11. Outputs & filters:
  12. -------------------------------------
  13. 0 - output([__values.C1], [__values.C2]), filter(nil),
  14. columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p0, p6)
  15. 1 - output([__values.C1], [__values.C2]), filter(nil)
  16. values({2, '200'}, {3, '300'})

上述示例的执行计划展示中的 outputs & filters 详细列出了 MULTI PARTITION INSERT 算子的信息,字段的含义与 INSERT 算子相同。

更多 MULTI PARTITION INSERT 算子的示例如下:

  • Q6 查询将子查询 SELECT * FROM t3 的结果插入到分区表 t2 中,因为无法确定子查询的结果集,因此数据可能插入到 t2 的 p0 到 p9 的任何一个分区中。从1 号算子可以看到,这里的 SELECT * FROM t3 会被放在一个子查询中,并将子查询命名为 VIEW1。当 OceanBase 数据库内部改写 SQL 产生了子查询时,会自动为子查询命名,并按照子查询生成的顺序命名为 VIEW1、VIEW2、VIEW3…

    1. Q6:
    2. obclient>EXPLAIN INSERT INTO t2 SELECT * FROM t3\G;
    3. *************************** 1. row ***************************
    4. Query Plan:
    5. ==============================================
    6. |ID|OPERATOR |NAME|EST. ROWS|COST|
    7. --------------------------------------------------
    8. |0 |MULTI PARTITION INSERT| |100000 |117862|
    9. |1 | EXCHANGE IN DISTR | |100000 |104060|
    10. |2 | EXCHANGE OUT DISTR | |100000 |75662 |
    11. |3 | SUBPLAN SCAN |VIEW1|100000 |75662 |
    12. |4 | TABLE SCAN |T3 |100000 |61860 |
    13. ==================================================
    14. Outputs & filters:
    15. -------------------------------------
    16. 0 - output([VIEW1.C1], [VIEW1.C2]), filter(nil),
    17. columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p[0-9])
    18. 1 - output([VIEW1.C1], [VIEW1.C2]), filter(nil)
    19. 2 - output([VIEW1.C1], [VIEW1.C2]), filter(nil)
    20. 3 - output([VIEW1.C1], [VIEW1.C2]), filter(nil),
    21. access([VIEW1.C1], [VIEW1.C2])
    22. 4 - output([T3.C1], [T3.C2]), filter(nil),
    23. access([T3.C2], [T3.C1]), partitions(p0)
  • Q7 查询将值(1, ‘100’)插入到非分区表 t3 中。虽然 t3 本身是一个非分区表,但因为 t3 上存在全局索引 idx_t3_c2,因此本次插入也涉及到了多个分区。

    1. Q7:
    2. obclient>EXPLAIN INSERT INTO t3 VALUES (1, '100')\G;
    3. *************************** 1. row ***************************
    4. Query Plan:
    5. ==============================================
    6. |ID|OPERATOR |NAME|EST. ROWS|COST|
    7. -----------------------------------------------
    8. |0 |MULTI PARTITION INSERT| |1 |1 |
    9. |1 | EXPRESSION | |1 |1 |
    10. ===============================================
    11. Outputs & filters:
    12. -------------------------------------
    13. 0 - output([__values.C1], [__values.C2]), filter(nil),
    14. columns([{T3: ({T3: (T3.C1, T3.C2)}, {IDX_T3_C2: (T3.C2, T3.C1)})}]), partitions(p0)
    15. 1 - output([__values.C1], [__values.C2]), filter(nil)
    16. values({1, '100'})