INSERT 算子用于将指定的数据插入数据表,数据来源包括直接指定的值和子查询的结果。
OceanBase 数据库支持的 INSERT 算子包括 INSERT 和 MULTI PARTITION INSERT。
INSERT
INSERT 算子用于向数据表的单个分区中插入数据。
如下例所示,Q1 查询将值 (1, '100') 插入到非分区表 t1 中。其中 1 号算子EXPRESSION 用来生成常量表达式的值。
obclient> CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT);
Query OK, 0 rows affected
obclient> CREATE TABLE t2 (c1 INT PRIMARY KEY, c2 INT) PARTITION BY
HASH(c1) PARTITIONS 10;
Query OK, 0 rows affected
obclient> CREATE TABLE t3 (c1 INT PRIMARY KEY, c2 INT);
Query OK, 0 rows affected
obclient> CREATE INDEX IDX_t3_c2 ON t3 (c2) PARTITION BY HASH(c2) PARTITIONS 3;
Query OK, 0 rows affected
Q1:
obclient> EXPLAIN INSERT INTO t1 VALUES (1, 100)\G
*************************** 1. row ***************************
Query Plan: ===========================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
-------------------------------------------
|0 |DISTRIBUTED INSERT| |1 |13 |
|1 | EXPRESSION | |1 |1 |
===========================================
Outputs & filters:
-------------------------------------
0 - output(nil), filter(nil),
columns([{t1: ({t1: (t1.c1, t1.c2)})}]),
column_values([column_conv(INT,PS:(11,0),NOT NULL,__values.c1)], [column_conv(INT,PS:(11,0),NULL,__values.c2)])
1 - output([__values.c1], [__values.c2]), filter(nil)
values({1, 100})
上述示例中,执行计划展示中的 outputs & filters 详细列出了 INSERT 算子的输出信息如下:
| 信息名称 | 含义 |
|---|---|
| output | 该算子输出的表达式。 |
| filter | 该算子上的过滤条件。 由于示例中 INSERT 算子没有设置 filter,所以为 nil。 |
| columns | 插入操作涉及的数据表的列。 |
| partitions | 插入操作涉及到的数据表的分区(非分区表可以认为是一个只有一个分区的分区表)。 |
更多 INSERT 算子的示例如下:
Q2 查询将值(2, 200)、(3, 300)插入到表
t1中。Q2: obclient> EXPLAIN INSERT INTO t1 VALUES (2, 200),(3, 300)\G *************************** 1. row *************************** Query Plan: =========================================== |ID|OPERATOR |NAME|EST. ROWS|COST| ------------------------------------------- |0 |DISTRIBUTED INSERT| |2 |20 | |1 | EXPRESSION | |2 |1 | =========================================== Outputs & filters: ------------------------------------- 0 - output(nil), filter(nil), columns([{t1: ({t1: (t1.c1, t1.c2)})}]), column_values([column_conv(INT,PS:(11,0),NOT NULL,__values.c1)], [column_conv(INT,PS:(11,0),NULL,__values.c2)]) 1 - output([__values.c1], [__values.c2]), filter(nil) values({2, 200}, {3, 300})Q3 查询将子查询
SELECT * FROM t3的结果插入到表t1中。Q3: obclient> EXPLAIN INSERT INTO t1 SELECT * FROM t3\G *************************** 1. row *************************** Query Plan: ================================================= |ID|OPERATOR |NAME |EST. ROWS|COST| ------------------------------------------------- |0 |INSERT | |1 |59 | |1 | SUBPLAN SCAN|ANONYMOUS_VIEW1|1 |46 | |2 | TABLE SCAN |t3 |1 |46 | ================================================= Outputs & filters: ------------------------------------- 0 - output(nil), filter(nil), columns([{t1: ({t1: (t1.c1, t1.c2)})}]), partitions(p0), column_values([column_conv(INT,PS:(11,0),NOT NULL,ANONYMOUS_VIEW1.c1)], [column_conv(INT,PS:(11,0),NULL,ANONYMOUS_VIEW1.c2)]) 1 - output([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]), filter(nil), rowset=256, access([ANONYMOUS_VIEW1.c1], [ANONYMOUS_VIEW1.c2]) 2 - output([t3.c1], [t3.c2]), filter(nil), rowset=256, access([t3.c1], [t3.c2]), partitions(p0)Q4 查询将值(1, '100')插入到分区表
t2中,通过partitions参数可以看出,该值会被插入到t2的p5分区。Q4: obclient> EXPLAIN INSERT INTO t2 VALUES (1, 100)\G *************************** 1. row *************************** Query Plan: ==================================== |ID|OPERATOR |NAME|EST. ROWS|COST| ------------------------------------ |0 |INSERT | |1 |1 | |1 | EXPRESSION| |1 |1 | ==================================== Outputs & filters: ------------------------------------- 0 - output([__values.C1], [__values.C2]), filter(nil), columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p5) 1 - output([__values.C1], [__values.C2]), filter(nil) values({1, '100'})
MULTI PARTITION INSERT
MULTI PARTITION INSERT 算子用于向数据表的多个分区中插入数据。
如下例所示,Q5 查询将值(2, '200')、(3, '300')插入到分区表 t2 中,通过 partitions 可以看出,这些值会被插入到 t2 的 p0 和 p6 分区。
Q5:
obclient> EXPLAIN INSERT INTO t2 VALUES (2, 200),(3, 300)\G
*************************** 1. row ***************************
Query Plan:
===============================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
-----------------------------------------------
|0 |MULTI PARTITION INSERT| |2 |1 |
|1 | EXPRESSION | |2 |1 |
===============================================
Outputs & filters:
-------------------------------------
0 - output([__values.C1], [__values.C2]), filter(nil),
columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p0, p6)
1 - output([__values.C1], [__values.C2]), filter(nil)
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...Q6: obclient> EXPLAIN INSERT INTO t2 SELECT * FROM t3\G *************************** 1. row *************************** Query Plan: ============================================== |ID|OPERATOR |NAME|EST. ROWS|COST| -------------------------------------------------- |0 |MULTI PARTITION INSERT| |100000 |117862| |1 | EXCHANGE IN DISTR | |100000 |104060| |2 | EXCHANGE OUT DISTR | |100000 |75662 | |3 | SUBPLAN SCAN |VIEW1|100000 |75662 | |4 | TABLE SCAN |T3 |100000 |61860 | ================================================== Outputs & filters: ------------------------------------- 0 - output([VIEW1.C1], [VIEW1.C2]), filter(nil), columns([{T2: ({T2: (T2.C1, T2.C2)})}]), partitions(p[0-9]) 1 - output([VIEW1.C1], [VIEW1.C2]), filter(nil) 2 - output([VIEW1.C1], [VIEW1.C2]), filter(nil) 3 - output([VIEW1.C1], [VIEW1.C2]), filter(nil), access([VIEW1.C1], [VIEW1.C2]) 4 - output([T3.C1], [T3.C2]), filter(nil), access([T3.C2], [T3.C1]), partitions(p0)Q7 查询将值(1, '100')插入到非分区表
t3中。虽然t3本身是一个非分区表,但因为t3上存在全局索引idx_t3_c2,因此本次插入也涉及到了多个分区。Q7: obclient> EXPLAIN INSERT INTO t3 VALUES (1, 100)\G *************************** 1. row *************************** Query Plan: ============================================== |ID|OPERATOR |NAME|EST. ROWS|COST| ----------------------------------------------- |0 |MULTI PARTITION INSERT| |1 |1 | |1 | EXPRESSION | |1 |1 | =============================================== Outputs & filters: ------------------------------------- 0 - output([__values.C1], [__values.C2]), filter(nil), columns([{T3: ({T3: (T3.C1, T3.C2)}, {IDX_T3_C2: (T3.C2, T3.C1)})}]), partitions(p0) 1 - output([__values.C1], [__values.C2]), filter(nil) values({1, '100'})




