Presto 设计与实现(十二):SQL 逻辑计划
1. 模拟 SQL 实现
之前通过下面的例子介绍了 SQL 语句从词法分析 -> 语法分析 -> 抽象语法树 AST 的过程:
我们稍微将 SQL 变得复杂一些,需求描述如下:
统计结果: 获取用户平均年龄最大的 10 个城市,输出城市名称、平均年龄、最大年龄和最小年龄;
限定条件 1 :用户年龄大于等于 18;
限定条件 2 :平均年龄大于 30。
通过使用过滤条件、分组相关函数、排序和限定条数,查询的 SQL 如下:
假设用户数据已经存储在 List 集合中,想实现类似 SQL 查询的效果,我们需要对集合进行过滤处理:
通过编码的方式模拟了 SQL 的查询,这就是 SQL 逻辑计划的主要思想,不过实际生成 SQL 逻辑计划的过程可能比这复杂的多。
2. 什么是逻辑计划
逻辑计划:通过对抽象语法树的遍历,将语法树上的 Node 节点转化成 1 个或多个有前后依赖关系的计划,节点遍历完毕即生成一个完整的计划链表,这就是逻辑计划。逻辑计划让 SQL 查询离数据库、表、列和数据更近了一步。
逻辑计划以抽象类 PlanNode 表示,具体的计划必须继承 PlanNode,这里面列举下和查询相关的计划:
TableScanNode:表的元数据信息,表和实际 connector 的绑定关系,表所有列的定义例如列名、类型、是否可空以及其他一些限定条件;
FilterNode:对应 WHERE 的过滤条件或者 HAVING 的过滤条件,过滤条件以抽象类 RowExpression 表示;
AggregationNode:分组的字段集合以及作用于列的分组函数;
SortNode:排序字段的名称和对应的排序标准;
LimitNode:返回的数据条数以及和列相关的表达式集合;
OutputNode:逻辑计划以 OutputNode 作为输出,同时也是生成的最后一个计划,定义了输出的列名和列相关的表达式集合;
ProjectNode:用于计划之间的衔接,和列相关表达式的溯源。
3. 逻辑计划生成过程
使用了上面的 SQL 生成了未经优化的逻辑计划,这里忽略了 ProjectNode:
4. 表达式类型
在 Presto 中表达式以抽象类 RowExpression 表示,RowExpression 有 6 种具体的实现:
VariableReferenceExpression:表达式的直接引用或更名;
ConstantExpression:和数值、字符串的有关的字面变量;
CallExpression:函数调用表达式,SQL 语句中涉及的所有函数,生成逻辑计划时创建该实例;
SpecialFormExpression:特殊形式表达式,条件表达式 CASE WHEN、IF、NULLIF、COALESCE、IN、AND 和 OR 等;
LambdaDefinitionExpression:lambda 表达式,对于某些函数 filter、map_filter、reduce 和 zip_with 等,lambda 表达式可作为参数传递:
版权声明: 本文为 InfoQ 作者【冰心的小屋】的原创文章。
原文链接:【http://xie.infoq.cn/article/b34ef454092f96c991a6e4e6e】。文章转载请联系作者。
评论