因谓词下推导致的查询结果不一致的问题分析--Hive
Hive中的谓词下推是一种优化技术,可以让Hive在查询时尽可能地将谓词下推到数据源中进行过滤,以减少数据的扫描和处理。然而,谓词下推有时也会导致查询结果不一致的问题。
1.问题描述
最近我们有个小伙伴在练习的习题的时候,因为自己的写法和提供的答案结果不一致,但是思路都是一致的,只是条件写的位置不太一样,就产生了疑惑。于是乎大家集思广益,提供了各种各样的思路。于是乎他做了多番尝,折腾出来四个典型的sql。
SQL1结果:20672和9721
SQL2结果:9721和9721
SQL3结果:20672和9721
SQL4结果:184125和9721

接下来,我们来分析分析原因。
2.Hive谓词下推
看到这里,相信很多小伙伴懂行的小伙伴都反应过来了:谓词下推!!!相信小伙伴学过光哥《hive企业性能调优实战》都会了解谓词下推的特性,那么什么是谓词下推呢?
简而言之,就是在不影响结果的情况下,尽量将过滤条件提前执行。谓词下推后,过滤条件在 map 端执行,减少了 map 端的输出,降低了数据在集群上传输的量,节约了集群的资源,也提升了任务的性能。其次谓词下推是 Hive 执行语法树的优化,优化了执行过程,本质是为了减少读取的数据量。
谓词下推对 SQL 代码编写的参考依据:
1. 对于 Join(Inner Join)、Full outer Join,条件写在 on 后面,还是where 后面,性能上面没有区别,Join(Inner Join)都下推,Full outer Join都不下推;
2. 对于 Left outer Join ,右侧的表写在 on 后面、左侧的表写在 where后面,性能上有提高;
3. 对于 Right outer Join,左侧的表写在 on 后面、右侧的表写在 where后面,性能上有提高;
引入思考:谓词下推还可以影响执行的结果?
3.问题分析
我们先来看四条sql的各自执行计划:
Sql1

Sql2

Sql3

Sql4

可以看出
1)我们的sql1中a表子查询一定先过滤,b表条件写在on中满足谓词下推,都进行各自的条件的过滤后,再进行了join,所以在count(disitnct t1.rold_id),count(distinct t2.role_id) 的时候,我们清晰的看到是分别count各自的过滤条件进行的数据。
2)我们的sql2 左表在where里,满足谓词下推,右表b也在where,不满足谓词下推,所以b表的条件是在join之后过滤,这就导致了所以在count(disitnct t1.rold_id),count(distinct t2.role_id) 的时候,都经历了右表b的条件过了,所以两个数据是一致的。
3)我们的sql3 左表a条件在where满足谓词下推,右表b在on满足谓词下推,所以都先进行了数据的过滤,在进行join的操作,和sql1一致:count(disitnct t1.rold_id),count(distinct t2.role_id) 的时候,我们清晰的看到是分别count各自的过滤条件进行的数据。
4)我们的sql4 左表a条件在on不满足谓词下推,b表条件在on里,满足过滤条件,这样,我们知道独针对左表的过滤条件必须放在 WHERE 上,放在 ON 上的效果是不可预期的,不生效;b表条件在on里满足谓词下推,生效,以在count(disitnct t1.rold_id),count(distinct t2.role_id) 的时候,a表示全量数据,b表是过滤后的数据。
通过上面的分析我们不难发现谓词下推确实都是生效的,但是在我们对最后结果的输出是因为执行顺序不同导入的结果不一致确实存在。但是这个异常也不是问题,我们想清楚自己想要什么结果,根据自己想要的结果进行选择。
4.问题总结
谓词下推是个好东西,确实可以通过调整条件放的位置来调整我们什么时候过滤数据,这是我们sql优化的利器;但是在我们left/right join的时候,同时输出两个关联表的结果时,一定要想清楚关联的两个表里各数据情况,自己想要什么结果样的结果。特别关注left/right join的情况:
更多精彩视频,数仓实战讲解可以关注我们视频号哈
结尾贴上一份Hive谓词下推的规则表:
