除了算子,为了代数运算符的完备性,我们还需要表达式计算。根据SQL语句的不同,表达式计算可能产生在每个算子上,用于进一步处理算子上的数据流,主要有以下两个功能:
过滤:根据表达式的逻辑,过滤掉不符合规则的数据。
投影:根据表达式的逻辑,对数据流进行表达式变换,产生新的数据。
表达式计算的核心是对于表达式树的遍历和计算,前面说到算子也是用树来表达执行计划。树这个基础的数据结构在执行器的流程中扮演了非常重要的位置。
我们看下面这个SQL:
SQL2:select w_id from warehouse where 2*w_tax + 0.9 > 1 and w_city != ‘Beijing’;
SQL语句where条件后面的就是SQL表达式,如果以树的形式表达展现成如图8-5所示。

图8-5 SQL语句树的表达形式
表达式计算对算子上的数据流进行计算,通过遍历表达式计算树完成整体的表达式计算对算子上的数据流进行计算,通过遍历表达式计算树完成整体的表达式计算,(为了便于说明,我们对上述表达式树每个节点进行了编号,见节点前的数字),可以看到上面的图里有些树节点中标注的是 Const,这代表这个节点是一个定值节点,存储了一个定值,有些节点中标注的是ExpOp,这代表这个节点是一个计算节点,根据表达式的不同有不同的计算方法,有些节点标注的是Col, 代表从表中的某个列中读取数据。上述的表达式计算的详细的流程如下:
(1) 根节点11代表一个AND操作符,AND逻辑是只要有一个子树的结果为false,则提前终止运算,否则进行下一个子树运算,下面有两个子表达式,我们先处理节点9, 首先递归遍历到其子节点3。
(2) 节点3代表了一个乘法,其有两个子节点1,2,从节点1列中取得w_tax的值,从节点2中取得定值2,然后进行乘法运算,计算数据存储到节点3引擎的一处暂存空间
(3) 节点5代表一个加法运算,其有两个子节点3,4,因此从表达式树节点4上取定值9,表达式3的结果刚才在第二步已经计算了,我们只需要读取出来,运算结果集存储到节点5暂存空间里。
(4) 节点9代表一个比较运算,其有两个子节点5, 6,因此将表达式树节点5存储的数据和树节点6上的数据定值1进行大于比较,如果结果为false,则提前终止当前的表达式运算,跳入下一行,重新从(1)开始计算,如果为true,则进行下一个子表达式的计算。
(5) 节点9已经处理完毕,我们接着处理节点10。
(6) 节点10代表字符串不等于比较运算,其有两个子节点7,8,从节点7中进行取得w_city值,同时从节点8中取得定值字符串“Beijing”, 然后进行不等于字符串比较运算,如果为true,输出tuple, 否则重新从(1)开始计算。
由此可见,通过遍历整个表达式树,根据表达式树不同节点的类型做出相应的动作,有些是对于数据的读取,有些是进行函数计算。表达式计算树叶子节点都来自数据流中的数据或者定值,而非叶子节点都是计算函数。




