OceanBase编译器部分

SQL执行分为5个步骤:

1.初始化
parse_init(&parse_res)

2.解析SQL语法树
parse_sql(&parse_res, stmt.ptr(), static_cast(stmt.length()));

3.制定逻辑计划
resolve(&logical_plan, parse_res.result_tree_)
ObMultiPlan* multi_plan = static_cast(logical_plan.plan_tree_);

4.生成物理计划:
trans.add_logical_plans(multi_plan);
physical_plan = trans.get_physical_plan(0)

5.执行物理计划:
exec_plan->open()

节点设计

语法树由一系列的节点串连而成。我选取较为简单的Insert语句作为示例,下面是一个例句:

insert into dytest values(1,'duyan');

其SQL语法树可以表示为:

|–Insert Stmt
|–T_IDENT:dytest
|–T_COLUMN_LIST:
|–T_IDENT:
|–NULL;
|–T_VALUE_LIST:
|–T_VALUE_VECTOR:
|–T_INT: 1
|–T_VALUE_VECTOR:
|–T_STRING: duyan

一.词法语法解析

首先介绍一下语法树的基本节点类型:
OceanBase 的语法树节点结构体只有一个,该结构体包括一个枚举类型变量type_,代表该结构体对应的类型。还有两组属性,对应终止符节点,只能使用value_和str_value_两个字段,分别对应64位整形值和字符串值;非终止符节点使用最后两个字段,num_child_表示子节点的个数,children_指向子节点数组的首地址。

Struct _ParseNode{
    ObItemType type;  //节点类型

    //叶子节点中的数据---终止符节点的真实的值
    int64_t value;   //数据长度
    const char* str_value; //实际值 

    //非叶子节点的数据---非终止符节点的孩子节点
    int32_t num_child_;  //孩子数
    struct _ParseNode** children_; //指向孩子的指针
}

当用户输入为:insert into dyrtest values(1,’duyanrong’)时,词法语法解析过程如下图所示:
OceanBase编译器部分_第1张图片
sql示例对应的语法树如下图所示:
OceanBase编译器部分_第2张图片
上图中的Insert语法树并不是完整的语法树,它只是insert into dyrtest values(1,’duyanrong’)这个insert请求对应的语法树。
可以通过阅读sql_parser.l和sql_parser.y文件得到insert对应的完整语法树,只是为了构造完整语法树,将insert的三个语法规则都考虑到了,最后结果如下图所示:
OceanBase编译器部分_第3张图片

|–ParseNode
|–type: T_Insert
|–num_child: 2
|–children[0]:
|–type: T_IDENT
|–str_value: dytest
|–children[1]:
|–type: T_VALUE_LIST
|–num_child:2
|–children[0]:
|–type: T_INT
|–int_value: 1
|–children[1]:
|–type: T_STRING
|–str_value: ”duyan”

但是仅仅语法树并不能知道数据库中是否存在dytest这张表,我们是否有权限修改这条记录等。语法树只能判断这条SQL的写法是否正确,不能确定这条SQL是否可以执行。

二.逻辑计划

逻辑计划需要明确SQL语句中所涉及到的表,字段,表达式等是否有效。这个的逻辑计划与在《数据库系统实现》等书中描述的逻辑查询计划不同。逻辑查询计划将SQL语句直接转为可运算的关系表达式。在OceanBase中,逻辑计划则只是查找或生成涉及到的表的ID,涉及字段的ID,涉及表达式的ID等,逻辑计划是不可运算的。

在ob中的函数调用如下图:
OceanBase编译器部分_第4张图片

//生成语法树,对传入的sql字符串进行词法语法解析,保存在ParseResult中
int parse_sql(ParseResult* p,const char* buf,size_t len)

//生成逻辑计划保存在ResultPlan中
int resolve(ResultPlan* result_plan,ParseNode* node)

三.语法树转逻辑执行计划

resolve_insert_stmt函数负责将insert的语法树转换成对应的逻辑执行计划!
resolve_insert_stmt函数从语法树的根节点开始,深度优先的处理语法树上的各个节点,将其中保存的sql信息转换成内部表示,即生成逻辑计划!

OceanBase编译器部分_第5张图片
可以看出,其实insert对应的逻辑计划,就是将sql的内容重新组织,用一种内部方式保存下来!
其中有两个数据结构是最重要的:

1.ObInsertStmt变量保存了insert操作涉及到的表和列的信息,例如里面保存了给哪个表的哪几列插入数据等;

2.ObSqlRawExpr则保存了insert操作涉及到的表达式信息,例如待插入表中的各个表达式的类型和结果值等。

四.逻辑执行计划转物理执行计划

物理查询计划能够直接执行并返回数据结果数据。它包含了一系列的基本操作,比如选择,投影,聚集,排序等。因此,本质上,物理查询计划是一系列数据操作的有序集合。为了更好的研究关系数据的操作,有人提出了关系代数模型。而物理查询计划的基本原理就来自于关系代数模型。

insert的物理执行计划可以理解为一种先前已经订好的模板!
添加逻辑计划,生成物理查询计划,示例代码如下:

//trans是转换类ObTransformer类,该类的功能就是将逻辑计划转换为物理查询计划。
trans.add_logical_plans(multi_plan);
physical_plan = trans.get_physical_plan(0);

insert的物理执行计划的抽象表示如下图所示:
OceanBase编译器部分_第6张图片

注意红色代表孩子操作符与父亲操作符的关系!
黑色代表操作符直接的存储顺序关系,它们是否有直接的调用关系,还得看物理树执行时的具体调用过程!
逻辑计划保存的信息主要被填充到了table_scan和input_values这两个物理操作符中了!

对insert的物理计划执行进行一个大体解释:
MergeServer 首先读取 ChunkServer 中的基线数据,并将基线数据中行是否存在信息发送给 UpdateServer。 UpdateServer 接着查看增量数据中行是否被删除或者有新的更新操作,融合基线数据和增量数据后,如果行不存在,则执行插入操作;否则,返回行已存在错误。
在这个动作里,去cs取基线数据是由table_scan完成的;input_values则保存了要插入的数据;而要发送给ups执行的物理计划,就是图中所示的inner_plan!

逻辑计划生成物理查询计划或物理操作符的操作由下面一系列函数完成.

    //物理查询计划生成函数  
    ObPhysicalPlan* ObTransformer::generate_physical_plan(ObLogicalPlan *logical_plan)  

    //select 语句-->物理查询计划  
    int64_t ObTransformer::gen_phy_mono_select  
    //order by -->排序运算符  
    ObPhyOperator* ObTransformer::gen_phy_order_by  
    //distinct-->去重运算符  
    ObPhyOperator* ObTransformer::gen_phy_distinct  
    //group by-->分组运算符  
    ObPhyOperator* ObTransformer::gen_phy_group_by  
    //聚集函数-->聚集运算符  
    ObPhyOperator* ObTransformer::gen_phy_scalar_aggregate  
    //表连接运算  
    int ObTransformer::gen_phy_joins  
    //from-->多表连接  
    int ObTransformer::gen_phy_tables  
    //表-->表扫描查询计划  
    ObPhyOperator* ObTransformer::gen_phy_table  
    //select语句-->物理查询计划,调用gen_phy_mono_select完成  
    ObPhysicalPlan* ObTransformer::gen_physical_select  
    //delete语句-->物理查询计划  
    ObPhysicalPlan* ObTransformer::gen_physical_delete  
    //insert语句-->物理查询计划  
    ObPhysicalPlan* ObTransformer::gen_physical_insert  
    //update语句-->物理查询计划  
    ObPhysicalPlan* ObTransformer::gen_physical_update  

图片来源网络,侵权删。

你可能感兴趣的:(OceanBase编译器部分)