这是我参与「第四届青训营 」笔记创作活动的的第1天
非常感谢字节提供了这样的一个学习大数据的机会。第一堂课主要关于SQL处理流程和优化器的知识,这里我们就详细讲述一下SQL处理流程。
平常用过数据库的同学,比如MySQL、Oracle、SQL Server等,对于SQL的编写肯定不会陌生。我们这里给出一段简单的SQL查询语句,主要是查询年龄小于40的用户的部门信息:
SELECT user.id, user.name, department.name
FROM user, department
WHERE user.department_id = department.id
AND user.age < 40;
以往我们直接将SQL语句发送给数据库引擎得到结果,并未关心他的具体实现流程。那这里我们就简单介绍一下,借用课上的流程图,数据库引擎得到SQL语句一直到输出结果,主要有如下四个步骤:
- Parser阶段:词法分析和语法分析,生成抽象语法树AST
- Analyzer阶段:合法性检查并转化为逻辑计划
- Optimizer阶段:找到代价最小的物理执行计划
- Executor阶段:执行并产生结果
1.Parser阶段
输入:SQL字符串
输出:AST抽象语法树
主要工作:
- 词法分析:将字符串拆分位一个个的单词,称之为Token
- 语法分析:将Token组装成抽象语法树
实现:递归下降(ClickHouse)、Flex和Bison(PostgreSQL)、JavaCC(Flink)、Antlr(Presto、Spark)
这里的词法分析和语法分析与编译原理中相似,根据SQL语法规则,将生成如下图所示的AST抽象语法树。主要可以拆分为select、from、where、group和order几部分。
2.Analyzer阶段
输入:AST抽象语法树
输出:逻辑计划
主要工作:
- 检查并绑定 Database、Table、Column 等元信息
- SQL合法性检查,比如 min、max、avg 的输入是数值
- 生成逻辑计划
逻辑计划(Logic Plan)指的是逻辑地描述SQL对应的分步骤的计算操作,这些操作被称为算子。 根据上面给出的SQL示例,有如下的逻辑计划:
stateDiagram-v2
SCAN1: SCAN
SCAN2: SCAN
Project --> FILTER
FILTER --> JOIN
JOIN --> SCAN1
JOIN --> SCAN2
note right of SCAN1: user
note right of SCAN2: department
这里用到了左偏树(Left Deep Tree)的数据结构,也可以称之为左偏堆,属于可并堆。 左偏树可以实现一般堆的所有操作,如查询最值,删除堆顶元素等,但是其具有时间复杂度为O(logn)的合并操作。 具备如下性质:
- 堆性质,即大根堆或者小根堆
- 左孩子距离叶子节点的最短距离大于右孩子距离叶子节点的最短距离
- 一个节点距离叶子节点的最短距离等于右孩子距离叶子节点的最短距离+1
3.Optimizer阶段
目标:找到一个正确且执行代价最小的物理执行计划
主要工作:按照最小化网络数据传输的目标将逻辑计划拆分为多个物理计划片段
这一部分是数据库的大脑,最重要的一块,很多问题都是NP的。对于大数据而言,查询优化的意义很大。同时,查询优化器需要感知数据分布,充分利用数据的亲和性,减少数据传递的消耗。
这里的查询优化器就是课程学习的重点了!
查询优化器根据不同的分类标准有不同的分类。 根据遍历计划树的方式,分为:
- Top-down Optimizer:自顶向下遍历,例如Volcano/Cascade、SQL Server
- Bottom-up Optimizer:自底向上遍历,例如System R、PostgreSQL、IBM DB2
根据优化方法,分为:
- Rule-based Optimizer(RBO):根据关系代数等价语义重写查询,基于启发式规则
- Cost-based Optimizer(CBO):使用模型估算执行计划的代价,选择代价最小的执行计划
课程中也详细介绍了RBO和CBO,下次单独拿出来讲。
4.Executor阶段
输入:物理执行计划
输出:执行
执行计划子树(Plan Fragment):
- 目标:最小化网络数据传输
- 利用数据物理分布,考虑数据亲和性
- 增加Shuffle算子
具体的Executor执行分为:
- 单机并行:cache、pipline、SIMD
- 多机并行:一个fragment对应多个实例
多机并行中,将每一个算子都定义为一个fragment,一个fragment计算需要的数据可能分布在多个节点,如果将数据都集中起来计算,将增加网络传输。因此,我们可以选择将该fragment在多个节点上运行。
总结:以上就是SQL处理过程中的四个主要步骤,分别是Parser、Analyzer、Optimizer和Executor阶段。通过将SQL语句拆分为Token并建立相应的抽象语法树,进而生成逻辑计划。数据库的核心就是对逻辑计划进行合理的优化,使用RBO或CBO等方法,优化执行计划的代价,最后生成一个合理的物理执行计划以执行得到最终的解。