RBO 的一个简单举例 | 青训营笔记

305 阅读3分钟

image.png

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

RBO

一、RBO的优化原则

  • Read data less and faster (IO)
  • Transfer data less and faster (Network)
  • Process data less and faster (CPU & Memory)

二、RBO的优化流程实例

有两张表 pvuser
对于下面这样一条 SQL 语句

SELECT pv.siteId, user.name
FROM pv JOIN user
ON pv.siteId = user.siteId AND pv.userId = user.id
WHERE user.siteId > 123;

优化前的逻辑任务如下图
image.png

RBO 是如何进行优化的呢?

  1. 列裁剪
    通过列裁剪,pv 表只需查询 siteIduserId 两个字段;user 表只需查询 idsiteIdname 三个字段。这样减少了数据的传输,而且如果底层的文件格式为列存(比如 Parquet),可以大大提高数据的扫描速度。
    经过列裁剪优化的逻辑计划如下图
    image.png

  2. 谓词下推
    谓词下推将 Filter 算子直接下推到 Join 之前,也就是在扫描 user 表的时候使用条件过滤出满足条件的数据。经过这样的操作,可以大大减少 Join 算子处理的数据量,从而加快计算速度。 经过谓词下推优化的逻辑计划如下图 image.png

  3. 传递闭包
    传递闭包根据 pv.siteId = user.siteId 这一条件,同时对 pv.siteId 进行过滤可以大大减少 Join 算子处理的数据量,加快计算速度。 经过传递闭包优化的逻辑计划如下图 image.png

  4. Runtime-Filter
    Runtime-Filter 指在进行Join的build端拉取数据的过程中新增了一个RuntimeFilterBuilder的一个算子,这个算子的作用就是在运行的过程中收集build端的信息形成runtime filter,runtime filter中可能包含的信息有最小-最大值、布隆过滤器等,并且发送到probe端的scan节点中去,让probe端的节点可以在scan就减少输入的数据,从而实现性能的提升。 经过 Runtime-Filter 优化的逻辑计划如下图 image.png

三、关于谓词下推的一些思考

是否所有情况都可以进行谓词下推?看下面的例子

SELECT s1.key, s2.key
FROM src s1 LEFT JOIN src s2
ON s1.key > '2';

其中left join中左表s1为保留行表,所以on条件(join过滤条件)不能下推到s1中

对于 Join 和 where 采用的谓词下推规则如下表image.png

同时需要注意的是,如果在表达式中含有不确定函数,整个表达式的谓词将不会被pushed,例如:

SELECT a.*
FROM a JOIN b
ON a.id = b.id
WHERE a.ds = '2019-10-09' AND a.create_time = unix_timestamp();

因为unix_timestamp是不确定函数,在编译的时候无法得知,所以,整个表达式不会被pushed,即ds='2019-10-09'也不会被提前过滤。类似的不确定函数还有rand()等。

四、小结

  • 主流 RBO 实现一般都有几百条基于经验归纳得到的优化规则
  • RBO 的优点:实现简单,优化速度快
  • RBO 的缺点:不能保证得到最优的执行计划

五、参考文献

[1] MySQL之谓词下推 - 等不到的口琴 - 博客园 (cnblogs.com)