因謂詞下推導(dǎo)致的查詢結(jié)果不一致的問題分析--Hive
Hive中的謂詞下推是一種優(yōu)化技術(shù),可以讓Hive在查詢時盡可能地將謂詞下推到數(shù)據(jù)源中進(jìn)行過濾,以減少數(shù)據(jù)的掃描和處理。然而,謂詞下推有時也會導(dǎo)致查詢結(jié)果不一致的問題。
1.問題描述
最近我們有個小伙伴在練習(xí)的習(xí)題的時候,因為自己的寫法和提供的答案結(jié)果不一致,但是思路都是一致的,只是條件寫的位置不太一樣,就產(chǎn)生了疑惑。于是乎大家集思廣益,提供了各種各樣的思路。于是乎他做了多番嘗,折騰出來四個典型的sql。
SQL1結(jié)果:20672和9721
SQL2結(jié)果:9721和9721
SQL3結(jié)果:20672和9721
SQL4結(jié)果:184125和9721

接下來,我們來分析分析原因。
2.Hive謂詞下推
看到這里,相信很多小伙伴懂行的小伙伴都反應(yīng)過來了:謂詞下推!?。∠嘈判』锇閷W(xué)過光哥《hive企業(yè)性能調(diào)優(yōu)實戰(zhàn)》都會了解謂詞下推的特性,那么什么是謂詞下推呢?
簡而言之,就是在不影響結(jié)果的情況下,盡量將過濾條件提前執(zhí)行。謂詞下推后,過濾條件在 map 端執(zhí)行,減少了 map 端的輸出,降低了數(shù)據(jù)在集群上傳輸?shù)牧?,?jié)約了集群的資源,也提升了任務(wù)的性能。其次謂詞下推是 Hive 執(zhí)行語法樹的優(yōu)化,優(yōu)化了執(zhí)行過程,本質(zhì)是為了減少讀取的數(shù)據(jù)量。
謂詞下推對 SQL 代碼編寫的參考依據(jù):
1. 對于 Join(Inner Join)、Full outer Join,條件寫在 on 后面,還是where 后面,性能上面沒有區(qū)別,Join(Inner Join)都下推,F(xiàn)ull outer Join都不下推;?
2. 對于 Left outer Join ,右側(cè)的表寫在 on 后面、左側(cè)的表寫在 where后面,性能上有提高;?
3. 對于 Right outer Join,左側(cè)的表寫在 on 后面、右側(cè)的表寫在 where后面,性能上有提高;
引入思考:謂詞下推還可以影響執(zhí)行的結(jié)果?
3.問題分析
我們先來看四條sql的各自執(zhí)行計劃:
Sql1

Sql2

Sql3

Sql4

可以看出
1)我們的sql1中a表子查詢一定先過濾,b表條件寫在on中滿足謂詞下推,都進(jìn)行各自的條件的過濾后,再進(jìn)行了join,所以在count(disitnct t1.rold_id),count(distinct t2.role_id) 的時候,我們清晰的看到是分別count各自的過濾條件進(jìn)行的數(shù)據(jù)。
2)我們的sql2 左表在where里,滿足謂詞下推,右表b也在where,不滿足謂詞下推,所以b表的條件是在join之后過濾,這就導(dǎo)致了所以在count(disitnct t1.rold_id),count(distinct t2.role_id) 的時候,都經(jīng)歷了右表b的條件過了,所以兩個數(shù)據(jù)是一致的。
3)我們的sql3 左表a條件在where滿足謂詞下推,右表b在on滿足謂詞下推,所以都先進(jìn)行了數(shù)據(jù)的過濾,在進(jìn)行join的操作,和sql1一致:count(disitnct t1.rold_id),count(distinct t2.role_id) 的時候,我們清晰的看到是分別count各自的過濾條件進(jìn)行的數(shù)據(jù)。
4)我們的sql4 左表a條件在on不滿足謂詞下推,b表條件在on里,滿足過濾條件,這樣,我們知道獨針對左表的過濾條件必須放在 WHERE 上,放在 ON 上的效果是不可預(yù)期的,不生效;b表條件在on里滿足謂詞下推,生效,以在count(disitnct t1.rold_id),count(distinct t2.role_id) 的時候,a表示全量數(shù)據(jù),b表是過濾后的數(shù)據(jù)。
通過上面的分析我們不難發(fā)現(xiàn)謂詞下推確實都是生效的,但是在我們對最后結(jié)果的輸出是因為執(zhí)行順序不同導(dǎo)入的結(jié)果不一致確實存在。但是這個異常也不是問題,我們想清楚自己想要什么結(jié)果,根據(jù)自己想要的結(jié)果進(jìn)行選擇。
4.問題總結(jié)
謂詞下推是個好東西,確實可以通過調(diào)整條件放的位置來調(diào)整我們什么時候過濾數(shù)據(jù),這是我們sql優(yōu)化的利器;但是在我們left/right ?join的時候,同時輸出兩個關(guān)聯(lián)表的結(jié)果時,一定要想清楚關(guān)聯(lián)的兩個表里各數(shù)據(jù)情況,自己想要什么結(jié)果樣的結(jié)果。特別關(guān)注left/right join的情況:
更多精彩視頻,數(shù)倉實戰(zhàn)講解可以關(guān)注我們視頻號哈
結(jié)尾貼上一份Hive謂詞下推的規(guī)則表:
