一滔吠、Join 邏輯計(jì)劃生成
和 Join 相關(guān)的邏輯層的優(yōu)化規(guī)則主要包含以下幾種:
ReorderJoin
EliminateOuterJoin
以及
中和 Join 相關(guān)的 predicate pushDown
二纲菌、Join 物理計(jì)劃生成和選取
2.1、基本概念
在 Spark SQL 中疮绷,參與 Join 操作的兩張表分別被稱為流式表(StreamTable)和構(gòu)件表(BuildTable)翰舌,不同表的角色在 Spark SQL 中會通過一定的策略進(jìn)行設(shè)定。通常來講冬骚,系統(tǒng)會將大表設(shè)置為 StreamTable椅贱,小表設(shè)置為 BuildTable。流式表的迭代器為 streamIter只冻,構(gòu)建表的迭代器為 buildIter庇麦。遍歷 streamIter 的每一條記錄,然后在 buildIter 中查找匹配的記錄喜德。這個(gè)查找過程稱為 build 過程山橄。每次 build 操作的結(jié)果為一條 JoinedRow(A, B)
,其中 A 來自 streamedIter住诸,B 來自 buildIter驾胆。
再例如涣澡,在 BroadcastHashJoin 中需要決定廣播哪個(gè)數(shù)據(jù)表。這里的 BuildSide 可以簡單理解為 “構(gòu)建的一邊”丧诺。
在 Spark 中入桂,BuildSide 作為一個(gè)抽象類,包含 BuildLeft 和 BuildRight 兩個(gè)子類驳阎,一般在構(gòu)造 Join 的執(zhí)行算子時(shí)抗愁,都會傳入一個(gè) BuildSide 的構(gòu)造參數(shù)。在 JoinSelection 中通過 canBuildRight
和 canBuildLeft
判斷一個(gè) Join 類型能否 “構(gòu)建” 右表和左表呵晚。
2.2蜘腌、物理計(jì)劃選取順序
Join 物理執(zhí)行計(jì)劃的選取在 JoinSelection 中進(jìn)行,其主要邏輯如下:
如果是一個(gè)等值 join(equi-join)且包含 join hint饵隙,我們依次查看 join hint:
-
broadcast hint
:如果 join 類型支持撮珠,使用 broadcast hash join。如果 left 和 right 都有 broadcast hint金矛,選擇 size 較小的一側(cè)(基于統(tǒng)計(jì)數(shù)據(jù))進(jìn)行 broadcast -
sort merge hint
:如果 join keys 是可排序的芯急,使用 sort merge join。 -
shuffle hash hint
:如果 join 類型支持驶俊,如果 left 和 right 都設(shè)置了 shuffle hash hints娶耍,選擇 size 較小的一側(cè)作為 build side -
shuffle replicate NL hint
:如果 join type 為 inner like,使用 cartesian product join(笛卡爾積)
JoinSelection 通過 ExtractEquiJoinKeys
來判斷是否為等值 Join 并提取相關(guān)信息:
如果沒有指定 hint 或 hint 不適用饼酿,Join 選擇順序如下:
- 嘗試選用 broadcast hash join:如果 join 類型支持榕酒,且 join 的一側(cè) size 足夠小能夠 broadcast。如果都足夠小故俐,選擇更小的一側(cè)進(jìn)行 broadcast(基于統(tǒng)計(jì)數(shù)據(jù))
- 嘗試選用 shuffle hash join:如果 join 類型支持想鹰,且 join 的一側(cè) size 足夠小能夠構(gòu)建 local hash map,且該側(cè) size 顯著小于另一側(cè)药版,且
spark.sql.join.preferSortMergeJoin
為 false - 嘗試選用 sort merge join:如果 join keys 是可排序的
- 嘗試選用笛卡爾積:如果是
inner like join
- 嘗試選用 broadcast nested loop join:最后的兜底手段杖挣,可能會 OOM,如果這里 OOM 了刚陡,也沒辦法了
2.3、等值 Join 情況
注①:
createJoinWithoutHint 如下: