【大資料】SparkSql 連線查詢中的謂詞下推處理 (二)

vivo網際網路技術發表於2019-06-04

本文首發於 vivo網際網路技術 微信公眾號 https://mp.weixin.qq.com/s/II48YxGfoursKVvdAXYbVg
作者:李勇

目錄:
1.左表 join 後條件下推
2.左表join中條件不下推
3.右表join中條件下推
4.右表join中條件不下推
5.總結

在《SparkSql連線查詢中的謂詞下推處理(一)》中,我們介紹了一些基本的概念,並對內連線查詢時的一些基本下推規則進行了分析。

本篇文章要介紹的是--外連線查詢中的謂詞下推規則,這相比內連線中的規則要複雜一些,不過使用簡單的表格來進行分析也是可以分析清楚的。先上表:

我們以左外連線查詢為例,先總結規矩如下:

接下來對這個表格中的規則進行詳細的分析。

1.左表join後條件下推

查詢語句如下:

前文有提到,對於join後條件,如果放在jo****in操作後執行,是可以作為正確結果進行比對的。那麼先對兩表進行左連線,結果如下:

然後使用LT.id>1這個join後條件進行過濾,結果如下:

來分析一下LT.id>1下推到左表進行資料過濾的結果,經過LT.id>1過濾後,左表變為:

此時再和右表進行左連線,左表id為2的行,在右表中能找到id為2的行,則連線結果如下:

可見,兩種處理方法結果一致。條件下推過濾了左表整整50%的資料(相當牛,雖然只過濾了一條)。究其原因,是因為在SparkSQL中,把以上的查詢解析成了如下的子查詢:

這是一個非相關子查詢,即完全可以先完成子查詢,再完成父查詢,子查詢在查詢過程中和外部查詢沒有關聯關係。

2.左表join中條件不下推

查詢語句如下:

來看看不下推的情況下計算出的正確結果,join過程如下:

第一步:左表id為1的行在右表中能找到相等的id,但是左表的id為1,是不滿足第二個join條件(LT.id>1)的,所以左表這一條相當於沒有和右表join上,所以左表的值value保留,而右表的valuenull(你沒滿足join中條件沒join上還把你的值保留,給我搞個空值?沒辦法,就是這麼任性)。

第二步:左表id為2的行在右表中能找到,而且左表id為2的行的id大於1,兩個join條件都滿足,所以算是和右表join上了,所以左表和右表的value都保留。最終的查詢結果如下:

那麼如果把"LT.id>1"這個條件下推到做表,會得到什麼結果呢?

首先左表經過"LT.id>1"過濾後,如下:

此時再和右表連線,左表id為2的行在右表中能找到,且滿足"LT.id = RT.id AND LT.id > 1"這個join中條件,所以兩表的value都被保留。左表中已經沒有資料了,查詢結束,查詢結果如下:

這個查詢結果和不下推的正確結果不一致,是個錯誤的結果,所以左表join中條件是不能下推進行資料過濾的。分析原因:主要是因為join中條件和join後條件對結果的處理方式不同,前者在不滿足join條件時會保留一部分結果,而後者在不滿足條件時任何東西都不保留。

3.右表join中條件下推

查詢語句如下:

現在把RT.id>1這個右表join後條件下推,來過濾右表,過濾後如下:

然後左表再和右表進行左連線,流程如下:

第一步:左表id為1的行在右表中沒有,此時左表值保留,右表為null

第二步:左表id位2的行在右表中有,並且RT.id大於1,兩個join條件都滿足,則左表和右表的值都保留。查詢結果如下:

那麼如果不下推(為了得到正確結果),來看看結果,流程如下:

第一步:左表id為1的行在右表中有,但是不滿足第二個join條件,所以這行算是沒join上,所以左表資料保留,右表為null

第二步:左表id為2的行在右表中有,也滿足第二個join條件,所以左右表的資料都保留。

可見,右表join中條件下推不下推,結果一樣,所以,幹嗎不下推?可以過濾掉一半的資料呢。SparkSQL中的等價處理語句是:

可以看出,也是解析成了一個非相關子查詢來處理的。

4.右表join中條件不下推

這個應該是最違反常規理解的查詢了,查詢語句如下:

首先來看,join後條件不下推的情況,流程如下:

第一步:左表id為1的行在右表中可以找到,但是此時僅僅滿足join條件,在使用where條件判斷這條連線後資料時,發現右表的id不滿足RT.id>1的條件,所以這條join結果不保留(注意:這裡是不保留,全都不保留,左表右表都不保留,要跟上邊的沒join上而右表的值保留為null的情況區別開,這也是關鍵所在);

第二步:左表id為2的行和右表id為2的行join上了,同時也滿足RT.id>1where條件。

這是一條符合語義的正確的查詢結果。

好了,接下來看看右表join後條件下推的情況:

第一步:使用RT.id>1過濾右表,過濾後右表只剩一行id為2的行;

第二步:左表id為1的行在過濾後的右表中沒有,此時左表值保留,右表值為null

第三步:左表id為2的行在右表中有,此時左表值保留,右表值也保留。

結果如下:

很明顯這其實是一個錯誤的結果。

總結

至此,左連線查詢的四條規則分析完了。可以看出,在SparkSQL中對於外連線查詢時的過濾條件,並不能在所有情況下都用來進行資料來源的過濾,如果使用得當會極大的提升查詢效能,如果使用不當,則會產生錯誤的查詢結果,而這種錯誤結果又不易發覺,所以使用時要格外小心。

更多內容敬請關注 vivo 網際網路技術 微信公眾號

注:轉載文章請先與微訊號:labs2020 聯絡。

相關文章