这是我参与「第四届青训营 」笔记创作活动的的第1天
1.SQL处理流程
在介绍SQL Optimizer之前,我们先来了解一下一条SQL的处理流程
graph LR
SQL-->Parser -->|AST| Analyzer--> |Logicial Plan|Optimizer -->|Physical Plan|Executor
- Parser
负责把SQL转换成抽象语法树AST,例如:select * from country where country.id=1
经过Parser解析后,会先将每个关键字生成对应的token,如select关键字经过解析后就会生成这样一个数据结构:
最后将多个token关联,组成AST。
- Analyzer
负责将AST转换成Logicial Plan(逻辑执行计划),以上面的SQL语句为例select * from country where country.id=1最终可以转换成:
graph TD
Projection -.- ScanTable
除此之外,Analyzer还负责检查SQL的合法性检查,例如表不存在,或者max/min输入有误等。
- Optimizer
优化器,也是SQL处理流程中最重要的一部分,现在主流处理的数据规模都可以达到PB,或者EB级别,在这个数据量下对SQL的优化就显得尤为重要,由于SQL语句只是指定了需要查找的目标,并没有限制我们用什么样的方法去实现,因此就有了Optimizer这一部分,它负责将Logical Plan转换成Physical Plan,并找到执行代价最小的。
- Executor
Executor是执行器,负责运行经过Optimizer优化后的物理计划,执行过程中可以将执行计划拆分成多个Fragment,并通过增加shuffle算子连接,它可以单机并行,也可以多机并行,在多机并行时需要考虑数据在网络传输中带来的开销,因此每个数据节点应该处理它本地的数据而不是其他节点的数据。
2. SQL Optimizer
介绍完SQL处理的大致流程,我们就可以深入探讨Optimzer中常见的查询优化器,主要有以下几种:
- Top-down Optimizer
- Bottom-up Optimizer
- Rule-base Optimizer
- Cost-base Optimizer
这里我们主要关注RBO以及CBO
- Rule-base Optimizer(RBO)
我们给出一条SQL语句SELECT pv.siteId, user.name FROM pv JOIN user ON pv.siteId = user.siteId AND pv.userId = user.id WHERE user.siteId > 123; 根据这条语句来讨论RBO的主要优化方式
1.列裁剪
可以看出在查询中,我们只用到了pv.siteId, pv.userId, user.name, user.siteId, user.id这5列,因此我们可以在查询操作前,先将表中的这5列筛选出来,这样对于有很多列的表来说,无疑大大减少了数据的开销。
2.谓词下推
在SQL语句中,类似user.siteId > 123这样的式子我们就可以称之为谓词,在执行计划中,这一部是在二表合并之后才执行的,但实际上我们将这条语句放在表连接前,在user表中执行,实际的结果是一样的,但是却减少了表连接带来的开销,这种操作就可以称之为谓词下推。
3.传递闭包
我们注意到pv.siteId = user.siteId, user.siteId > 123这二条语句,可以推导出pv.siteId > 123,跟上面的思路类似,我们也就可以将pv表提前过滤,在查询初期就缩减表的规模。
4.Runtime filter
也是得益于pv.siteId = user.siteId AND pv.userId = user.id这个限制,我们可以确认这2个对值的数据范围应该是有交集的,在user.siteId > 123执行完成后,我们可以根据得到的结果来限制pv表中的数据,主要可以通过这3种方式:min-max、in-list、bloom filter。
在数值范围波动不大的情况下如user.siteId值在1~100之间,采用min-max就有很好的效果,但如果数值范围为1 ~1000000,而实际上1000000只有一个数,其他数都在1-100,这种情况下,min-max过滤就起不到什么作用了,与之相比,in-list将在这种情况下就更加实用,它将user.siteId值存入表中,再拿去和pv表做比对,这样就不会有范围过大的困扰,但在数据较多的情况下也形同虚设。
- Cost-base Optimizer(CBO)
CBO的执行流程大致如下:
graph LR
统计信息 --> 计算算子代价 --> 计算执行代价-->执行计划枚举
统计信息主要以处理行数,占用字节,行大小,选择率(selectivity),基数(cardinality)为基准来统计代价,再由特定算法计算出算子代价以及执行代价,得出所有的执行代价后,再从中选出代价最小的一条,作为最优的执行计划。