1. RDD 之痛:優(yōu)化空間受限
RDD 的核心痛點(diǎn)是優(yōu)化空間有限晨仑,它指的是 RDD 高階算子中封裝的函數(shù)對(duì)于 Spark 來說完全透明,因此 Spark 對(duì)于計(jì)算邏輯的優(yōu)化無從下手拆檬。相比 RDD洪己,DataFrame 是攜帶 Schema 的分布式數(shù)據(jù)集,只能封裝結(jié)構(gòu)化數(shù)據(jù)竟贯。DataFrame 的算子大多數(shù)都是普通的標(biāo)量函數(shù)拱镐,以消費(fèi)數(shù)據(jù)列為主。但是,DataFrame 更弱的表示能力和表達(dá)能力空繁,反而為 Spark 引擎的內(nèi)核優(yōu)化打開了全新的空間娱颊。根據(jù) DataFrame 簡單的標(biāo)量算子和明確的 Schema 定義剧罩,借助 Catalyst 優(yōu)化器和 Tungsten,Spark SQL 有能力在運(yùn)行時(shí),構(gòu)建起一套端到端的優(yōu)化機(jī)制。這套機(jī)制運(yùn)用啟發(fā)式的規(guī)則與策略和運(yùn)行時(shí)的執(zhí)行信息,將原本次優(yōu)证鸥、甚至是低效的查詢計(jì)劃轉(zhuǎn)換為高效的執(zhí)行計(jì)劃鸟蜡,從而提升端到端的執(zhí)行性能
2. Catalyst邏輯計(jì)劃
- Catalyst 邏輯優(yōu)化階段分為兩個(gè)環(huán)節(jié):邏輯計(jì)劃解析和邏輯計(jì)劃優(yōu)化。在邏輯計(jì)劃解析中,Catalyst 把“Unresolved Logical Plan”轉(zhuǎn)換為“Analyzed Logical Plan”;在邏輯計(jì)劃優(yōu)化中倍试,Catalyst 基于一些既定的啟發(fā)式規(guī)則(Heuristics Based Rules)准颓,把“Analyzed Logical Plan”轉(zhuǎn)換為“Optimized Logical Plan”样勃。
- 在邏輯計(jì)劃解析環(huán)節(jié)植锉,Catalyst 就是要結(jié)合 DataFrame 的 Schema 信息辉饱,來確認(rèn)計(jì)劃中的表名、字段名、字段類型與實(shí)際數(shù)據(jù)是否一致匪补。完成確認(rèn)之后,Catalyst 會(huì)生成“Analyzed Logical Plan”捏境。
- 生成“Analyzed Logical Plan”之后蚌成,Catalyst 并不會(huì)止步于此瓶盛,它會(huì)基于一套啟發(fā)式的規(guī)則吵取,把“Analyzed Logical Plan”轉(zhuǎn)換為“Optimized Logical Plan”
Catalyst 的優(yōu)化規(guī)則
- 謂詞下推(Predicate Pushdown):“下推”指代的是把這些謂詞沿著執(zhí)行計(jì)劃向下剪撬,推到離數(shù)據(jù)源最近的地方,從而在源頭就減少數(shù)據(jù)掃描量
- 列剪裁(Column Pruning):列剪裁就是掃描數(shù)據(jù)源的時(shí)候旦委,只讀取那些與查詢相關(guān)的字段(列式存儲(chǔ)才行)
- 常量替換 (Constant Folding):摻雜了一些常量表達(dá)式,Catalyst 也會(huì)自動(dòng)地用表達(dá)式的結(jié)果進(jìn)行替換
Cache Manager 優(yōu)化
這里的 Cache 指的就是我們常說的分布式數(shù)據(jù)緩存之斯。想要對(duì)數(shù)據(jù)進(jìn)行緩存,你可以調(diào)用 DataFrame 的.cache 或.persist,或是在 SQL 語句中使用“cache table”關(guān)鍵字涝滴。Cache Manager 其實(shí)很簡單,它的主要職責(zé)是維護(hù)與緩存有關(guān)的信息济竹。具體來說闭树,Cache Manager 維護(hù)了一個(gè) Mapping 映射字典,字典的 Key 是邏輯計(jì)劃慢睡,Value 是對(duì)應(yīng)的 Cache 元信息复凳。當(dāng) Catalyst 嘗試對(duì)邏輯計(jì)劃做優(yōu)化時(shí),會(huì)先嘗試對(duì) Cache Manager 查找签则,看看當(dāng)前的邏輯計(jì)劃或是邏輯計(jì)劃分支扛拨,是否已經(jīng)被記錄在 Cache Manager 的字典里。如果在字典中可以查到當(dāng)前計(jì)劃或是分支场钉,Catalyst 就用 InMemoryRelation 節(jié)點(diǎn)來替換整個(gè)計(jì)劃或是計(jì)劃的一部分得封,從而充分利用已有的緩存數(shù)據(jù)做優(yōu)化手形。
3. Catalyst物理計(jì)劃
優(yōu)化 Spark Plan
-
Catalyst 都有哪些 Join 策略艘虎?
結(jié)合 Joins 的實(shí)現(xiàn)機(jī)制和數(shù)據(jù)的分發(fā)方式,Catalyst 在運(yùn)行時(shí)總共支持 5 種 Join 策略缭付,分別是 Broadcast Hash Join(BHJ)、Shuffle Sort Merge Join(SMJ)、Shuffle Hash Join(SHJ)、Broadcast Nested Loop Join(BNLJ)和 Shuffle Cartesian Product Join(CPJ)坷牛。
5種Join策略及其含義
如果開發(fā)者不滿足于 JoinSelection 默認(rèn)的選擇順序,也就是 BHJ > SMJ > SHJ > BNLJ > CPJ月劈,還可以通過在 SQL 或是 DSL 語句中引入 Join hints褐缠,來明確地指定 Join 策略器躏,從而把自己的意愿凌駕于 Catalyst 之上揽浙。不過钓猬,需要我們注意的是剧劝,要想讓指定的 Join 策略在運(yùn)行時(shí)生效茵休,查詢語句也必須要滿足其先決條件才行。
5種Join策略的先決條件
生成 Physical Plan
從 Spark Plan 到 Physical Plan 的轉(zhuǎn)換手蝎,需要幾組叫做 Preparation Rules 的規(guī)則榕莺。這些規(guī)則堅(jiān)守最后一班崗,負(fù)責(zé)生成 Physical Plan棵介。那么钉鸯,這些規(guī)則都是什么,它們都做了哪些事情呢邮辽?
4. 鎢絲計(jì)劃:Tungsten(重要)
Unsafe Row:二進(jìn)制數(shù)據(jù)結(jié)構(gòu)
基于內(nèi)存頁的內(nèi)存管理
如何理解 WSCG唠雕?
什么是火山迭代模型?
WSCG 的優(yōu)勢是什么吨述?
WSCG 是如何在運(yùn)行時(shí)動(dòng)態(tài)生成代碼的岩睁?
5. AQE的3個(gè)特性
為什么需要 AQE?
- 啟發(fā)式的優(yōu)化又叫 RBO(Rule Based Optimization揣云,基于規(guī)則的優(yōu)化)捕儒,它往往基于一些規(guī)則和策略實(shí)現(xiàn),如謂詞下推邓夕、列剪枝刘莹,這些規(guī)則和策略來源于數(shù)據(jù)庫領(lǐng)域已有的應(yīng)用經(jīng)驗(yàn)阎毅。也就是說,啟發(fā)式的優(yōu)化實(shí)際上算是一種經(jīng)驗(yàn)主義栋猖。
- CBO 的特點(diǎn)是“實(shí)事求是”净薛,基于數(shù)據(jù)表的統(tǒng)計(jì)信息(如表大小、數(shù)據(jù)列分布)來選擇優(yōu)化策略蒲拉。如果在運(yùn)行時(shí)數(shù)據(jù)分布發(fā)生動(dòng)態(tài)變化肃拜,CBO 先前制定的執(zhí)行計(jì)劃并不會(huì)跟著調(diào)整、適配雌团。
AQE是什么燃领?
AQE 是 Spark SQL 的一種動(dòng)態(tài)優(yōu)化機(jī)制,在運(yùn)行時(shí)锦援,每當(dāng) Shuffle Map 階段執(zhí)行完畢猛蔽,AQE 都會(huì)結(jié)合這個(gè)階段的統(tǒng)計(jì)信息,基于既定的規(guī)則動(dòng)態(tài)地調(diào)整灵寺、修正尚未執(zhí)行的邏輯計(jì)劃和物理計(jì)劃曼库,來完成對(duì)原始查詢語句的運(yùn)行時(shí)優(yōu)化。
- AQE 賴以優(yōu)化的統(tǒng)計(jì)信息與 CBO 不同略板,這些統(tǒng)計(jì)信息并不是關(guān)于某張表或是哪個(gè)列毁枯,而是 Shuffle Map 階段輸出的中間文件。每個(gè) Map Task 都會(huì)輸出以 data 為后綴的數(shù)據(jù)文件叮称,還有以 index 為結(jié)尾的索引文件种玛,這些文件統(tǒng)稱為中間文件。每個(gè) data 文件的大小瓤檐、空文件數(shù)量與占比赂韵、每個(gè) Reduce Task 對(duì)應(yīng)的分區(qū)大小,所有這些基于中間文件的統(tǒng)計(jì)值構(gòu)成了 AQE 進(jìn)行優(yōu)化的信息來源
-
結(jié)合 Spark SQL 端到端優(yōu)化流程圖我們可以看到挠蛉,AQE 從運(yùn)行時(shí)獲取統(tǒng)計(jì)信息祭示,在條件允許的情況下,優(yōu)化決策會(huì)分別作用到邏輯計(jì)劃和物理計(jì)劃碌秸。
AQE 既定的規(guī)則和策略
Join 策略調(diào)整
DemoteBroadcastHashJoin 規(guī)則的作用绍移,是把 Shuffle Joins 降級(jí)為 Broadcast Joins。需要注意的是讥电,這個(gè)規(guī)則僅適用于 Shuffle Sort Merge Join 這種關(guān)聯(lián)機(jī)制蹂窖,其他機(jī)制如 Shuffle Hash Join、Shuffle Nested Loop Join 都不支持恩敌。
- spark.sql.autoBroadcastJoinThreshold 中間文件尺寸總和小于廣播閾值
- spark.sql.adaptive.nonEmptyPartitionRatioForBroadcastJoin 空文件占比小于配置項(xiàng)
自動(dòng)分區(qū)合并
在 Reduce 階段瞬测,當(dāng) Reduce Task 從全網(wǎng)把數(shù)據(jù)分片拉回,AQE 按照分區(qū)編號(hào)的順序,依次把小于目標(biāo)尺寸的分區(qū)合并在一起
- spark.sql.adaptive.advisoryPartitionSizeInBytes月趟,由開發(fā)者指定分區(qū)合并后的推薦尺寸灯蝴。
- spark.sql.adaptive.coalescePartitions.minPartitionNum,分區(qū)合并后孝宗,分區(qū)數(shù)不能低于該值穷躁。
自動(dòng)傾斜處理
在 Reduce 階段,當(dāng) Reduce Task 所需處理的分區(qū)尺寸大于一定閾值時(shí)因妇,利用 OptimizeSkewedJoin 策略问潭,AQE 會(huì)把大分區(qū)拆成多個(gè)小分區(qū)。
- spark.sql.adaptive.skewJoin.skewedPartitionFactor婚被,判定傾斜的膨脹系數(shù)
- spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes狡忙,判定傾斜的最低閾值
- spark.sql.adaptive.advisoryPartitionSizeInBytes,以字節(jié)為單位址芯,定義拆分粒度
6. DPP特性
分區(qū)剪裁
相比于謂詞下推灾茁,分區(qū)剪裁往往能更好地提升磁盤訪問的 I/O 效率。謂詞下推操作往往是根據(jù)文件注腳中的統(tǒng)計(jì)信息完成對(duì)文件的過濾谷炸,過濾效果取決于文件中內(nèi)容的“純度”北专。分區(qū)剪裁則不同,它的分區(qū)表可以把包含不同內(nèi)容的文件旬陡,隔離到不同的文件系統(tǒng)目錄下逗余。這樣一來,包含分區(qū)鍵的過濾條件能夠以文件系統(tǒng)目錄為粒度對(duì)磁盤文件進(jìn)行過濾季惩,從而大幅提升磁盤訪問的 I/O 效率。
動(dòng)態(tài)分區(qū)剪裁
動(dòng)態(tài)分區(qū)剪裁運(yùn)作的背后邏輯腻格,是把維度表中的過濾條件画拾,通過關(guān)聯(lián)關(guān)系傳導(dǎo)到事實(shí)表,來完成事實(shí)表的優(yōu)化菜职。在數(shù)據(jù)關(guān)聯(lián)的場景中青抛,開發(fā)者要想利用好動(dòng)態(tài)分區(qū)剪裁特性,需要注意 3 點(diǎn):
- 事實(shí)表必須是分區(qū)表酬核,并且分區(qū)字段必須包含 Join Key
- 動(dòng)態(tài)分區(qū)剪裁只支持等值 Joins蜜另,不支持大于、小于這種不等值關(guān)聯(lián)關(guān)系
- 維度表過濾之后的數(shù)據(jù)集嫡意,必須要小于廣播閾值举瑰,注意調(diào)整配置項(xiàng) spark.sql.autoBroadcastJoinThreshold
7. Join Hints
NLJ 的工作原理(NLJ 算法的計(jì)算復(fù)雜度是 O(M * N))
NLJ 是采用“嵌套循環(huán)”的方式來實(shí)現(xiàn)關(guān)聯(lián)的。也就是說蔬螟,NLJ 會(huì)使用內(nèi)此迅、外兩個(gè)嵌套的 for 循環(huán)依次掃描外表和內(nèi)表中的數(shù)據(jù)記錄,判斷關(guān)聯(lián)條件是否滿足
SMJ 的工作原理(SMJ 算法的計(jì)算復(fù)雜度為 O(M + N))
SMJ 的思路是先排序、再歸并耸序。具體來說忍些,就是參與 Join 的兩張表先分別按照 Join Key 做升序排序。然后坎怪,SMJ 會(huì)使用兩個(gè)獨(dú)立的游標(biāo)對(duì)排好序的兩張表完成歸并關(guān)聯(lián)罢坝。
- 外表 Join Key 等于內(nèi)表 Join Key,滿足關(guān)聯(lián)條件搅窿,把兩邊的數(shù)據(jù)記錄拼接并輸出嘁酿,然后把外表的游標(biāo)滑動(dòng)到下一條記錄
- 外表 Join Key 小于內(nèi)表 Join Key,不滿足關(guān)聯(lián)條件戈钢,把外表的游標(biāo)滑動(dòng)到下一條記錄
- 外表 Join Key 大于內(nèi)表 Join Key痹仙,不滿足關(guān)聯(lián)條件,把內(nèi)表的游標(biāo)滑動(dòng)到下一條記錄
HJ 的工作原理(內(nèi)表掃描的計(jì)算復(fù)雜度為O(1))
- HJ 的計(jì)算分為兩個(gè)階段殉了,分別是 Build 階段和 Probe 階段开仰。在 Build 階段,基于內(nèi)表薪铜,算法使用既定的哈希函數(shù)構(gòu)建哈希表
-
在 Probe 階段众弓,算法遍歷每一條數(shù)據(jù)記錄,先是使用同樣的哈希函數(shù)隔箍,以動(dòng)態(tài)的方式(On The Fly)計(jì)算 Join Key 的哈希值谓娃。然后,用計(jì)算得到的哈希值去查詢剛剛在 Build 階段創(chuàng)建好的哈希表蜒滩。如果查詢失敗滨达,說明該條記錄與維度表中的數(shù)據(jù)不存在關(guān)聯(lián)關(guān)系;如果查詢成功俯艰,則繼續(xù)對(duì)比兩邊的 Join Key捡遍。如果 Join Key 一致,就把兩邊的記錄進(jìn)行拼接并輸出竹握,從而完成數(shù)據(jù)關(guān)聯(lián)画株。
小結(jié)
分布式環(huán)境下的 Join
Spark 如何選擇 Join 策略?
- 在等值數(shù)據(jù)關(guān)聯(lián)中啦辐,Spark 會(huì)嘗試按照 BHJ > SMJ > SHJ 的順序依次選擇 Join 策略谓传。在這三種策略中,執(zhí)行效率最高的是 BHJ芹关,其次是 SHJ续挟,再次是 SMJ。其中侥衬,SMJ 和 SHJ 策略支持所有連接類型庸推,如全連接常侦、Anti Join 等等。BHJ 盡管效率最高贬媒,但是有兩個(gè)前提條件:一是連接類型不能是全連接(Full Outer Join)聋亡;二是基表要足夠小,可以放到廣播變量里面去际乘。
- SHJ 策略要想被選中必須要滿足兩個(gè)先決條件坡倔,這兩個(gè)條件都是對(duì)數(shù)據(jù)尺寸的要求。首先脖含,外表大小至少是內(nèi)表的 3 倍罪塔。其次,內(nèi)表數(shù)據(jù)分片的平均大小要小于廣播變量閾值养葵。第一個(gè)條件的動(dòng)機(jī)很好理解征堪,只有當(dāng)內(nèi)外表的尺寸懸殊到一定程度時(shí),HJ 的優(yōu)勢才會(huì)比 SMJ 更顯著关拒。第二個(gè)限制的目的是佃蚜,確保內(nèi)表的每一個(gè)數(shù)據(jù)分片都能全部放進(jìn)內(nèi)存。
- 由于不等值 Join 只能使用 NLJ 來實(shí)現(xiàn)着绊,因此 Spark SQL 可選的 Join 策略只剩下 BNLJ 和 CPJ谐算。在同一種計(jì)算模式下,相比 Shuffle归露,廣播的網(wǎng)絡(luò)開銷更小洲脂。顯然,在兩種策略的選擇上剧包,Spark SQL 一定會(huì)按照 BNLJ > CPJ 的順序進(jìn)行嘗試恐锦。當(dāng)然,BNLJ 生效的前提自然是內(nèi)表小到可以放進(jìn)廣播變量疆液。如果這個(gè)條件不成立踩蔚,那么 Spark SQL 只好委曲求全,使用笨重的 CPJ 策略去完成關(guān)聯(lián)計(jì)算枚粘。
8. 大表Join小表
案例 1:Join Key 遠(yuǎn)大于 Payload
先用 Hash Key 取代 Join Keys飘蚯,再清除內(nèi)表冗余數(shù)據(jù)馍迄。Hash Key 實(shí)際上是 Join Keys 拼接之后的哈希值。既然存在哈希運(yùn)算局骤,我們就必須要考慮哈希沖突的問題攀圈。
案例 2:過濾條件的 Selectivity 較高
AQE 允許 Spark SQL 在運(yùn)行時(shí)動(dòng)態(tài)地調(diào)整 Join 策略。我們剛好可以利用這個(gè)特性峦甩,把最初制定的 SMJ 策略轉(zhuǎn)化為 BHJ 策略
案例 3:小表數(shù)據(jù)分布均勻
當(dāng)參與 Join 的兩張表尺寸相差懸殊且小表數(shù)據(jù)分布均勻的時(shí)候赘来,SHJ 往往比 SMJ 的執(zhí)行效率更高现喳。這種情況下,我們不妨使用 Join Hints 來強(qiáng)制 Spark SQL 去選擇 SHJ 策略進(jìn)行關(guān)聯(lián)計(jì)算
9. 大表Join大表
如何理解“分而治之”犬辰?
先把一個(gè)復(fù)雜任務(wù)拆解成多個(gè)簡單任務(wù)嗦篱,再合并多個(gè)簡單任務(wù)的計(jì)算結(jié)果蓄愁。首先溅漾,我們要根據(jù)兩張表的尺寸大小區(qū)分出外表和內(nèi)表练俐。一般來說殴蓬,內(nèi)表是尺寸較小的那一方死相。然后侮措,我們?nèi)藶榈卦趦?nèi)表上添加過濾條件肚吏,把內(nèi)表劃分為多個(gè)不重復(fù)的完整子集涎劈。接著轿偎,我們讓外表依次與這些子集做關(guān)聯(lián)典鸡,得到部分計(jì)算結(jié)果。最后坏晦,再用 Union 操作把所有的部分結(jié)果合并到一起萝玷,得到完整的計(jì)算結(jié)果,這就是端到端的關(guān)聯(lián)計(jì)算英遭。
如何保證內(nèi)表拆分的粒度足夠細(xì)间护?
“分而治之”中一個(gè)關(guān)鍵的環(huán)節(jié)就是內(nèi)表拆分,我們要求每一個(gè)子表的尺寸相對(duì)均勻挖诸,且都小到可以放進(jìn)廣播變量汁尺。拆分的關(guān)鍵在于拆分列的選取,為了讓子表足夠小多律,拆分列的基數(shù)(Cardinality)要足夠大才行痴突。
如何避免外表的重復(fù)掃描?
對(duì)于外表參與的每一個(gè)子關(guān)聯(lián)狼荞,在邏輯上辽装,我們完全可以只掃描那些與內(nèi)表子表相關(guān)的外表數(shù)據(jù),并不需要每次都掃描外表的全量數(shù)據(jù)相味。
數(shù)據(jù)分布均勻
- 兩張表數(shù)據(jù)分布均勻拾积。
- 內(nèi)表所有數(shù)據(jù)分片,能夠完全放入內(nèi)存丰涉。
以 Task 為粒度解決數(shù)據(jù)傾斜
有了 AQE 的自動(dòng)傾斜處理特性拓巧,在應(yīng)對(duì)數(shù)據(jù)傾斜問題的時(shí)候,我們確實(shí)能夠大幅節(jié)省開發(fā)成本一死。不過肛度,天下沒有免費(fèi)的午餐,AQE 的傾斜處理是以 Task 為粒度的投慈,這意味著原本 Executors 之間的負(fù)載傾斜并沒有得到根本改善
以 Executor 為粒度解決數(shù)據(jù)傾斜
“兩階段 Shuffle”
如何理解“兩階段 Shuffle”承耿?
“兩階段 Shuffle”指的是冠骄,通過“加鹽、Shuffle加袋、關(guān)聯(lián)凛辣、聚合”與“去鹽化、Shuffle锁荔、聚合”這兩個(gè)階段的計(jì)算過程蟀给,在不破壞原有關(guān)聯(lián)關(guān)系的前提下,在集群范圍內(nèi)以 Executors 為粒度平衡計(jì)算負(fù)載 阳堕。
10. 補(bǔ)充
- Java Object 在對(duì)象存儲(chǔ)上為什么會(huì)有比較大的開銷跋理?JVM 需要多少個(gè)字節(jié)才能存下字符串“abcd”? https://databricks.com/blog/2015/04/28/project-tungsten-bringing-spark-closer-to-bare-metal.html
- 對(duì)于復(fù)雜的業(yè)務(wù)邏輯恬总,如果DSL和SQL都無法實(shí)現(xiàn)前普,除了UDF,其實(shí)還可以考慮用Script Transformation https://databricks.com/session_eu19/powering-custom-apps-at-facebook-using-spark-script-transformation
- 標(biāo)量函數(shù)和標(biāo)量算子
- 3 種 Join 實(shí)現(xiàn)方式和 2 種網(wǎng)絡(luò)分發(fā)模式壹堰,明明應(yīng)該有 6 種 Join 策略拭卿,為什么 Catalyst 沒有支持 Broadcast Sort Merge Join 策略?
- 一個(gè)action對(duì)應(yīng)一個(gè)job贱纠,但是經(jīng)常一個(gè)action被拆分成了兩三個(gè)相同的job(task數(shù)量可能會(huì)有不同)峻厚,并且有時(shí)候好多job還是可以skip的。這又涉及了Spark的哪些優(yōu)化機(jī)制呢谆焊?
- Block Nested-Loop Join(BNL) 惠桃,非等值連接?
- EnsureRequirements 規(guī)則辖试?
- 針對(duì)排序操作辜王,你認(rèn)為 Tungsten 在數(shù)據(jù)結(jié)構(gòu)方面有哪些改進(jìn)呢?
- 你認(rèn)為表達(dá)式代碼生成(Expression Codegen)和全階段代碼生成(Whole Stage Codegen)有什么區(qū)別和聯(lián)系呢罐孝?
- 如果事實(shí)表的join字段有好幾個(gè)呐馆,其中只有一個(gè)是分區(qū)字段,那還能享受到DPP嗎莲兢?
- DPP 的機(jī)制就是將經(jīng)過過濾后的維度表廣播到事實(shí)表進(jìn)行裁剪汹来,減少掃描數(shù)據(jù),但 Spark 怎么才知道哪個(gè)是維度表哪個(gè)是事實(shí)表改艇?
- 不等值 Join 可以強(qiáng)行用 Sort Merge Join 和 Hash Join 兩種機(jī)制來實(shí)現(xiàn)嗎收班?排序和構(gòu)建hash table本身成了開銷,在不等值的情況下遣耍,已經(jīng)沒有任何意義。
- 對(duì)于案例 1炮车,我們的核心思路是用哈希值來替代超長的 Join Keys舵变,除了用哈希值以外酣溃,你覺得還有其他的思路或是辦法,去用較短的字符串來取代超長的 Join Keys 嗎纪隙?
- 對(duì)于案例 3赊豌,假設(shè) 20GB 的小表存在數(shù)據(jù)傾斜,強(qiáng)行把 SMJ 轉(zhuǎn)化為 SHJ 會(huì)拋 OOM 異常绵咱。這個(gè)時(shí)候碘饼,你認(rèn)為還有可能繼續(xù)優(yōu)化嗎?
- DPP機(jī)制的觸發(fā)條件非潮妫苛刻艾恼,怎么結(jié)合業(yè)務(wù)來使用DPP機(jī)制帶來的優(yōu)化好處,例如在業(yè)務(wù)中經(jīng)常使用ID作為join 的條件麸锉,顯然是不能作為分區(qū)的钠绍,那么是否可以取id的尾值等等的思路吧
- 兩階段 Shuffle,理解加鹽解決了什么問題