数据库在接收到 SQL 查询时,必须为其生成一个“执行计划”。OceanBase 数据库的执行计划与其他关系数据库类似,本质上是由物理操作符构成的一棵执行树。物理操作符一般对应一个关系操作,如表扫描、连接、聚合、排序等。执行计划通过将不同的物理操作符按照一定的先后顺序组织在一棵执行树中,最终完成该 SQL 查询。
物理操作符
执行计划在 OceanBase 数据库中被实现为一棵由物理操作符组成的树,目前 OceanBase 数据库支持 zigzag 形状的计划树。
物理操作符是执行计划的基本单元,多个物理操作符按照“二叉树”的形式组成一个完整的执计划。
常见的物理操作符如下表所示:
类型 | 物理操作符 |
表访问 | table scan,table get |
Join | NLJ, BNLJ,MJ, HJ |
排序 | sort,top-n sort |
聚合 | merge group-by,hash group-by |
分布式 | exchange in/out |
集合 | union, except, intersect |
其他 | limit, material, subplan,expression |
执行计划的 DML 语句
数据操纵语言(Data Manipulation Language, DML)是 SQL 语言中,负责对数据库对象运行数据访问工作的指令集。它的三种核心指令:INSERT(插入)、UPDATE(更新)、DELETE(删除)。除此之外,OceanBase 数据库还支持 REPLACE 和 INSERT INTO…ON DUPLICATED KEY UPDATE 两种 DML 语句,DML 的主要功能是访问数据,因此其语法都是以读取与写入数据库为主,除了 INSERT 以外,其他指令都可能需搭配 WHERE 指令来过滤数据范围,或是不加 WHERE 指令来访问全部的数据。
在 OceanBase 数据库中,所有的 DML 语句都会生成对应的执行计划来进行数据的读写操作,每一种 DML 语句都会生成一种对应的 DML 算子。DML 算子负责读取数据,并通过存储层提供的数据写入接口将 DML 语句涉及到的数据写入存储引擎中。对于 INSERT/REPLACE 语句而言,由于其不用读取表中的已有数据,因此,INSERT 语句的执行计划相对简单,其执行计划为简单的 EXPR VALUES+INSERT OP 算子构成。而对于 UPDATE 或者 DELETE 语句而言,优化器会通过代价模型对 WHERE 条件进行访问路径的选择,或者 ORDER BY 数据顺序的选择,详细选择方式请参见访问路径。
INSERT 执行计划示例
create table t1(a int primary key, b int, index idx1(b));
explain insert into t1 values(1, 1), (2, 2);
| ====================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
------------------------------------
|0 |INSERT | |0 |0 |
|1 | EXPRESSION| |0 |0 |
====================================
Outputs & filters:
-------------------------------------
0 - output([column_conv(INT,PS:(11,0),NOT NULL,__values.a)], [column_conv(INT,PS:(11,0),NULL,__values.b)]), filter(nil),
columns([t1.a], [t1.b]), partitions(p0)
1 - output([__values.a], [__values.b]), filter(nil)
values({1, 1}, {2, 2})
|
UPDATE 执行计划示例
create table t1(a int primary key, b int, index idx1(b));
explain update t1 set b=10 where b=1;
| =======================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
---------------------------------------
|0 |UPDATE | |1 |37 |
|1 | TABLE SCAN|t1(idx)|1 |36 |
=======================================
Outputs & filters:
-------------------------------------
0 - output(nil), filter(nil), params([{t1: (t1.a, t1.b)}]), update([t1.b=?])
1 - output([t1.a], [t1.b], [?]), filter(nil),
access([t1.b], [t1.a]), partitions(p0)
|
DELETE 执行计划示例
create table t1(a int primary key, b int, index idx1(b));
explain delete from t1 where b=1;
| ========================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
----------------------------------------
|0 |DELETE | |2 |39 |
|1 | TABLE SCAN|t1(idx1)|2 |37 |
========================================
Outputs & filters:
-------------------------------------
0 - output(nil), filter(nil), params([{t1: (t1.a, t1.b)}])
1 - output([t1.a], [t1.b]), filter(nil),
access([t1.a], [t1.b]), partitions(p0)
|