「SQL Optimizer 解析」|青训营笔记

118 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的的第1天!

整体概念构建

一、数据库组成
数据库主要由三部分组成,分别是解析器(Parser)、优化器(Optimizer)和执行引擎(Execution Engine),如下图:

image.png 其中优化器是数据库中用于把关系表达式转换成执行计划的核心组件,很大程度上决定了一个系统的性能。

二、查询优化器的分类

  • 基于规则的优化器(Rule-Based Optimizer,RBO)

根据优化规则对关系表达式进行转换,这里的转换是说一个关系表达式经过优化规则后会变成另外一个关系表达式,同时原有表达式会被裁剪掉,经过一系列转换后生成最终的执行计划。
RBO中包含了一套有着严格顺序的优化规则,同样一条SQL,无论读取的表中数据是怎么样的,最后生成的执行计划都是一样的。同时,在RBO中SQL写法的不同很有可能影响最终的执行计划,从而影响脚本性能。
RBO的两个主要思路是:减少参与计算的数据量、降低重复计算的代价。RBO相对于CBO而言要成熟得多,常用的规则都基于经验制定,可以覆盖大部分查询场景,并且方便扩展。其缺点则是不够灵活,毕竟这个阶段对物理上的特征(如表的底层存储形式和真正的数据量)还没有感知。 主流的RBO实现一般都有几百条基于经验归纳得到的优化规则。

3种最常见也是最有效的RBO方式:\

常量折叠(ConstantFolding)
在编译阶段,对该变量进行值替换,同时,该常量拥有自己的内存空间,并非像宏定义一样不分配空间。

谓词下推(PushdownPredicate)
如果能够将SQL语句中的谓词逻辑(where条件、join on中的谓词条件)都尽量提前执行,下游处理已经过滤完毕的数据,能够减少工作量。

列裁剪(ColumnPruning)
列裁剪的基本思想在于:对于算子中实际用不上的列,优化器在优化的过程中没有必要保留它们。对这些列的删除会减少 I/O 资源占用,并为后续的优化带来便利。 在未优化的逻辑计划中,Join Inner与Filter操作符都会扫描很多列,然后再由Project操作符筛选出结果列。但实际上,我们可以在初始单独扫描表时就只筛选出符合后续逻辑计划的最小列集合,同样能够节省很多资源。如果表物理上是用Parquet、ORC等列式存储格式持久化的,效率就会更高。

  • 基于代价的优化器(Cost-Based Optimizer,CBO)

根据优化规则对关系表达式进行转换,这里的转换是说一个关系表达式经过优化规则后会生成另外一个关系表达式,同时原有表达式也会保留,经过一系列转换后会生成多个执行计划,然后CBO会根据统计信息和代价模型(Cost Model)计算每个执行计划的Cost,从中挑选Cost最小的执行计划。

由上可知,CBO中有两个依赖:统计信息和代价模型。统计信息的准确与否、代价模型的合理与否都会影响CBO选择最优计划。

同时,CBO常使用贪心或者动态规划算法寻找最优执行计划

总体而言,CBO是优于RBO的,原因是RBO是一种只认规则,对数据不敏感的呆板的优化器,而在实际过程中,数据往往是有变化的,通过RBO生成的执行计划很有可能不是最优的。\

社区开源实践

主要了解Apache Calcite,其是一个独立于存储与执行的SQL优化引擎,广泛应用于开源大数据计算引擎中,如Flink、Drill、Hive、Kylin等。另外,MaxCompute也使用了Calcite作为优化器框架。Calcite的架构如下图所示:

download.png

其中Operator Expressions 指的是关系表达式,一个关系表达式在Calcite中被表示为RelNode,往往以根节点代表整个查询树。Calcite中有两种方法生成RelNode:\

  • 通过Parser直接解析生成

从上述架构图可以看到,Calcite也提供了Parser用于SQL解析,直接使用Parser就能得到RelNode Tree。

  • 通过Expressions Builder转换生成

不同系统语法有差异,所以Parser也可能不同。针对这种情况,Calcite提供了Expressions Builder来对抽象语法树(或其他数据结构)进行转换得到RelNode Tree。如Hive(某一种Data Processing System)使用的就是这种方法。
Query Optimizer 根据优化规则(Pluggable Rules)对Operator Expressions进行一系列的等价转换,生成不同的执行计划,最后选择代价最小的执行计划,其中代价计算时会用到Metadata Providers提供的统计信息。
事实上,Calcite提供了RBO和CBO两种优化方式,分别对应HepPlanner和VolcanoPlanner。

前沿趋势

一、引擎架构的进化

存储计算分离
一体化(HTAP、HSAP、HTSAP)

二、Cloud云原生

serverless

三、湖仓一体

Query Federation

四、DATA + AI

AI4DB
-自配置(智能调参、负载预测/调度)
-自诊断和自愈合:错误恢复和迁移
-自优化(统计信息估计、代价估计、学习型优化器、索引/视图推荐)

DB4AI
-内嵌人工智能算法(MLSQL,SQLFlow)
-内嵌机器学习框架(SparkML、Alink、dl-on-flink)

个人思考

现在大数据、云计算的热度愈来愈热,随着数据的爆发式增长以及对于数据的存储,处理,分类的需求日益高涨,大数据方面会发展进步的更快,RBO的渐渐淘汰正印证了此需求。

参考

SQL优化器原理——查询优化器综述 - 知乎 (zhihu.com)