谓词下推

proginn222750

共 2098字,需浏览 5分钟

 ·

2021-07-31 03:23

谓词下推

什么是谓词

在SQL中,谓词是返回boolean值(即true和false)的函数,或者是隐式转换为bool的函数。SQL中的谓词主要有like、between、is null、is not null、in、exists等。

什么是谓词下推

谓词下推,即将用来过滤的表达式,尽可能的移动至靠近数据源的位置,以使真正执行的时候能够直接跳过无关的数据。

传统数据库

在传统数据库中,谓词下推作为优化手段很早就出现了,谓词下推的目的就是通过将一些过滤条件尽可能的在最底层执行,以减少每一层交互的数据量,从而提升查询性能。

例如:

select count(1) from A join B on A.id = B.id where A.a > 10 and B.b<100;

在处理Join操作前,需要先对A和B执行TableScan操作,然后再进行Join,再进行过滤,最后计算聚合函数返回。但是,如果把过滤条件 A.a>10 和 B.b<100 分别移到A表的TableScan和B表的TableScan的时候执行,可以大大降低Join操作的输入数据量。

优化后的语句如下:

select count(1) from (select * from A where A.a>10) A1 join (select * from B where B.b<100) B1 on A1.id = B1.id;

无论是行式存储还是列式存储,都可以将过滤条件在读取一条记录后执行以判断是否需要返回给调用者,在Parquet中做了更进一步的优化,优化的方法是,对每一个Row Group的每一个Column Chunk在存储时都计算相应的统计信息,包括该Column Chunk的最大值、最小值和空值个数。通过这些统计值和该列的过滤条件可以判断该Row Group是否需要扫描。另外Parquet还将增加Bloom Filter和Index优化等特性,更加有效的完成谓词下推。

Hive中的谓词下推

Predicate Pushdown

在谓词下推后,过滤条件在map端执行,减少了map端的输出,降低了数据在集群上传输的量,节约了集群的资源,也提升了任务的性能。

对应的参数配置为:

hive.optimize.pdd = true

参数默认为true,即开启谓词下推。

PDD(Predicate Pushdown)规则

规则1:

  • During Join predicates cannot be pushed past Preserved Row tables.

   join条件过滤不能下推到保留行表中。

select s1.key, s2.key from src s1 left join src s2 on s1.key > '2';

在上述SQL语句中,left join中左表s1为保留行表,所以on条件(join过滤条件)不能下推到s1中,而s2表不是保留行表,所以s2.key>2条件可以下推到s2表中:

select s1.key, s2.key from src s1 left join src s2 on s2.key > '2';

规则2:

  • After Join predicates cannot be pushed past Null Supplying tables.

   where条件过滤不能下推到NULL补充表。

select s1.key, s2.key from src s1 left join src s2 where s1.key > '2';

在上面的SQL语句中,left join中的右表s2为NULL补充表,s1.key>2可以下推到s1,而由于s2为NULL补充表,所以s2.key>2过滤条件不能下推到s2中:

select s1.key, s2.key from src s1 left join src s2 where s2.key > '2';
总结

9ba44d890c88f38c3b00a84867a3eb04.webp

  • 对于Join、Full Outer Join,条件写在on后面还是where后面,性能上没有区别

  • 对于left join,右侧表的写在on后面,左侧的表写在where后面,性能有提高

  • 对于right join,左侧的表写在on后面,右侧的表写在where后面,性能有提高

  • 所谓下推,即谓词过滤是在map端执行;所谓不下推,即谓词过滤在reduce端执行

  • 需要注意的是,如果表达式中含有不确定函数,整个表达式的谓词都不会被下推,比如:

    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()等。


浏览 54
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报