淘宝数据库OceanBaseSQL编译器部分源码阅读--生成逻辑计划(一)

2014-11-24 16:57:27 · 作者: · 浏览: 2

淘宝数据库OceanBase SQL编译器部分 源码阅读--生成逻辑计划

SQL编译解析三部曲分为:构建语法树,生成逻辑计划,指定物理执行计划。第一步骤,在我的上一篇博客淘宝数据库OceanBase SQL编译器部分 源码阅读--解析SQL语法树里做了介绍,这篇博客主要研究第二步,生成逻辑计划。

一、 什么是逻辑计划?

我们已经知道,语法树就是一个树状的结构组织,每个节点代表一种类型的语法含义。如
update student set sex="M" where name ="小明";
这条SQL的语法树形状为:

|Update Stmt
|----Table:student
|----TargeList:
|--------sex = "M"
|----Qualifications:
|--------name="小明"

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

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

二、逻辑计划包含哪些内容?

简单来说,逻辑计划要弄清楚,这条SQL可以分解为几条stmt,每条stmt包含了哪些表,字段和表达式。在此基础上,如果是insert的Stmt,要加上设置哪些值;如果是update的stmt,要加上需要更新的列和对应的值,等等。

在一个逻辑计划中,每一个查询有一个唯一标识qid,每一张表有一个唯一的标识tid,每一个列有一个唯一的标识cid,每一个表达式有一个唯一的标识eid

来看OceanBase中的逻辑计划的结构(省略无关方法和变量).

 class ObLogicalPlan
    {
      //...  
      oceanbase::common::ObVector stmts_; //存储该逻辑计划的所有stmt
      oceanbase::common::ObVector exprs_; //逻辑计划的所有表达式
      oceanbase::common::ObVector raw_exprs_store_;//存储逻辑计划的所有表达式
      uint64_t  new_gen_tid_;//用于生成新的tid
      uint64_t  new_gen_cid_;//用于生成新的cid
      uint64_t  new_gen_qid_;//用于生成新的qid
      uint64_t  new_gen_eid_;//用于生成新的eid
    };

oceanbase::common::ObVector是OceanBase中自己实现的泛型容器之一,作用与STL的vector相同。
stmts_存储该逻辑计划的所有stmt;
raw_exprs_store_仅仅用于存储表达式,exprs_则引用raw_exprs_store_中的内容。
new_gen_tid_等4个变量是用来生成新的标识时使用,一个逻辑是可以用多个tid,多个cid,多个eid,多个qid的。这些标识分布于存储的stmt和表达式中

注:stmt实在不知道中文该怎么称呼,就不改中文名了。

2.1 逻辑计划中表的定义

struct TableItem
{
    uint64_t    table_id_;
    common::ObString    table_name_;
    common::ObString    alias_name_;
    TableType   type_;

    uint64_t     ref_id_;
};

table_id_唯一标识一个关系表,其类型分为基本表,引用表和子查询关系。
对同一个实体表,ref_id_与table_id_相同; 如果是一个引用别名的表,则table_id_是新生成的,ref_id_与这个表真正的table_id_相同;如果是一个子查询,则table_id_是新生成的,ref_id_是对子查询的引用。

对同一个实体表,它在所有线程使用的table_id_都是相同的;如果是生成的标识,则仅在该线程会话期间是唯一的。

2.2 逻辑计划中列的定义

struct ColumnItem
{
    uint64_t    column_id_;
    common::ObString    column_name_;
    uint64_t    table_id_;
    uint64_t    query_id_;

    bool        is_name_unique_;
    bool        is_group_based_;

    common::ObObjType     data_type_;
};

column_id_唯一标识一个列,table_id_和query_id_为该列所属的关系表和stmt。is_name_unique_仅用在解析逻辑计划期间,标记该列的名称是否在所有表的字段中都是唯一的。is_group_based_标记该列是否用于分组。data_type_标识该列的数据类型。

2.3 逻辑计划中的表达式的定义

逻辑计划的中表达式有多种类型,其基类为ObRawExpr.包括两个成员变量,type_表示表达式的类型,result_type_表示表达式值的类型。

 class ObRawExpr
 {
 //省略其他方法
 private:
    ObItemType  type_;
    common::ObObjType result_type_;
 }

表达式分为常量表达式, 一元引用表达式,二元引用表达式,一元操作符表达式,二元操作符表达式,三元操作符表达式,多元操作符表达式,case操作符表达式,聚集函数表达式,系统函数表达式,SQL原生表达式等。继承关系如下。

namespace sql
{
     //原生表达式基类
    class ObRawExpr
    //常量表达式
    class ObConstRawExpr        : public ObRawExpr
    //一元引用表达式
    class ObUnaryRefRawExpr     : public ObRawExpr
    //二元引用表达式
    class ObBinaryRefRawExpr    : public ObRawExpr
    //一元操作符表达式
    class ObUnaryOpRawExpr      : public ObRawExpr
    //二元操作符表达式
    class ObBinaryOpRawExpr     : public ObRawExpr
     //三元操作符表达式
    class ObTripleOpRawExpr     : public ObRawExpr
    //多元操作符表达式
    class ObMultiOpRawExpr      : public ObRawExpr
    //case操作符表达式
    class ObCaseOpRawExpr       : public ObRawExpr
    //聚集函数表达式
    class ObAggFunRawExpr       : public ObRawExpr
    //系统函数表达式
    class ObSysFunRawExpr       : public ObRawExpr
    //SQL原生表达式
    class ObSqlRawExpr          : public ObRawExpr
 };

 class Ob