这是我参与「第四届青训营 」笔记创作活动的的第2天
[第四届青训营笔记创作活动]
RBO
一、RBO的优化原则
- Read data less and faster (IO)
- Transfer data less and faster (Network)
- Process data less and faster (CPU & Memory)
二、RBO的优化流程实例
有两张表 pv 和 user
对于下面这样一条 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 是如何进行优化的呢?
-
列裁剪
通过列裁剪,pv表只需查询siteId和userId两个字段;user表只需查询id、siteId和name三个字段。这样减少了数据的传输,而且如果底层的文件格式为列存(比如 Parquet),可以大大提高数据的扫描速度。
经过列裁剪优化的逻辑计划如下图
-
谓词下推
谓词下推将 Filter 算子直接下推到 Join 之前,也就是在扫描user表的时候使用条件过滤出满足条件的数据。经过这样的操作,可以大大减少 Join 算子处理的数据量,从而加快计算速度。 经过谓词下推优化的逻辑计划如下图 -
传递闭包
传递闭包根据pv.siteId = user.siteId这一条件,同时对pv.siteId进行过滤,可以大大减少 Join 算子处理的数据量,加快计算速度。 经过传递闭包优化的逻辑计划如下图 -
Runtime-Filter
Runtime-Filter 指在进行Join的build端拉取数据的过程中新增了一个RuntimeFilterBuilder的一个算子,这个算子的作用就是在运行的过程中收集build端的信息形成runtime filter,runtime filter中可能包含的信息有最小-最大值、布隆过滤器等,并且发送到probe端的scan节点中去,让probe端的节点可以在scan就减少输入的数据,从而实现性能的提升。 经过 Runtime-Filter 优化的逻辑计划如下图
三、关于谓词下推的一些思考
是否所有情况都可以进行谓词下推?看下面的例子
SELECT s1.key, s2.key
FROM src s1 LEFT JOIN src s2
ON s1.key > '2';
其中left join中左表s1为保留行表,所以on条件(join过滤条件)不能下推到s1中
对于 Join 和 where 采用的谓词下推规则如下表:
同时需要注意的是,如果在表达式中含有不确定函数,整个表达式的谓词将不会被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 的缺点:不能保证得到最优的执行计划