SQL Optimizer 解析 课程笔记|青训营笔记

151 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的的第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关键字经过解析后就会生成这样一个数据结构:

ast.png

最后将多个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中常见的查询优化器,主要有以下几种:

  1. Top-down Optimizer
  2. Bottom-up Optimizer
  3. Rule-base Optimizer
  4. 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)为基准来统计代价,再由特定算法计算出算子代价以及执行代价,得出所有的执行代价后,再从中选出代价最小的一条,作为最优的执行计划。