查询优化器(RBO) | 青训营笔记
这是我参与「第四届青训营 」笔记创作活动的的第2天
常见的查询优化器
查询优化器的分类(两种分类方法)
-
Top-down Optimizer
- 从目标输出开始,由上往下遍历计划树,找到完整的最优执行计划
- 例子: Volcano/Cascade,SQLServer
-
Bottom-up Optimizer
- 从零开始,由下往上遍历计划树,找到完整的执行计划
- 例子: System R,PostgreSQL,IBM DB2
-
Rule-based Optimizer (RBO)
- 根据关系代数等价语义,重写查询
- 基于启发式规则
- 会访问表的元信息(catalog),不会涉及具体的表数据(data)
-
Cost-based Optimizer (CBO)
- 使用一个模型估算执行计划的代价,选择代价最小的执行计划
RBO (Rule-based Optimizer)
关系代数
即基于关系代数的等价变换
运算符:
等价变换:结合律,交换律,传递性
优化原则
Read data less and faster (I/o) Transfer data less and faster (Network) Process data less and faster (CPU & Memory)
目的是一个查询跑得快,因此需要一些优化的目标。整体上可以分为三点,可以优化它的I/O,(希望读更少数据,读数据的时候更快)、优化网络,(希望传输的数据更少,传输数据也更快)、优化它的cpu和内存,(希望处理数据的时候,cpu的指指定数更少,内存使用更少,重叠数据更少)
优化逻辑计划。
列裁剪
基本思想:
对于一个查询,相对应的算子实际上用不到列,那么在进行计算的时候是不需要去读取去保留它们,因此尽早的这些列去掉,减少一些I/O或者是内存的占用,然后为后续的优化带来便利。
这个优化从上了往下扫描,计算算子需要哪些列,继而传递FILTER,再加上FILTER自己需要的列,再和上层传递下来的列组成一个新的集合,继而继续往下传递。
谓词下推
在上述条件里面的表达式就称为谓词。在一个需要过滤数据的查询,需要在更早的形面过滤,或者说在更后面过滤它,在某些场景下它的结果是不受影响,都是正确的,因此希望把这个位置尽可能下推,尽早的过滤数据,过滤掉一些不必要的数据,不必要的函数有效的减少传输或者计算的开销。
传递闭包
基本思想:根据一些等价关系再加上一些过滤条件,可以推导出一个新的过滤条件。
结构图:
举例解释: 传递闭包——从左边到右边的转化
实则左边是经过列裁结,经过谓词下推之后的一个执行计划
右边可以推导出一个新的FILTER——可以把pv的SCAN往下推,推过这个JOIN就得到了右边一个执行计划
继而把现有的FILTER往下推,同时产生了一个新的FILTER,JOIN的两边其实都经过了FILTER的过滤,数据量会减少很多,那么做连接操作的时候会很快。
Runtime Filter
即这是一个运行时的FILTER,只有在运行时才能产生FILTER。广泛运用在数据库中。
原理:对于单个JOIN,希望在PO(即查询端)去查询表里面数据是不是存在的思想。可以提早过滤左边的数据,可以去进行预算,,减少许多不必要的数据,减少开销
比如JOIN是通过一个哈希表来实现,右端是已经构建好的哈希表应用,左边是一个遍历关系。哈希表需要计算哈希Code,同时还有比较操作。
核心思想——Runtime Filter能不能产生新的FILTER,下推到JOIN的查询端。
小结
-
主流RBO实现一般都有几百条基于经验归纳得到的优化规则
-
优点:实现简单,优化速度快
-
缺点:不保证得到最优的执行计划
-
单表扫描:索引扫描(随机I/O) vs.全表扫描(顺序I/O)
- 如果查询的数据分布非常不均衡,索引扫描可能不如全表扫描
-
Join的实现:Hash Join vs. SortMerge Join
-
两表Hash Join:用小表构建哈希表——如何识别小表?(做不到)
-
多表Join:
-
哪种连接顺序是最优的?
-
是否要对每种组合都探索?
- N个表连接,仅仅是left-deep tree就有差不多N!种连接顺序
- e.g. N= 10->总共3,628,800个连接顺序
-
-
-

浙公网安备 33010602011771号