一般的join如果兩邊的join條件是一一對(duì)應(yīng)是性能比較好的情況,但是當(dāng)遇到j(luò)oin條件兩邊存在多行對(duì)應(yīng)一行或者多行對(duì)應(yīng)多行的情況。就會(huì)出現(xiàn)M行join N行? ?結(jié)果就會(huì)產(chǎn)生笛卡爾積M*N行。如果M和N都不大還好。通過(guò)shuffle到磁盤一樣能計(jì)算出來(lái)。但是如果M和N都很大而且不止兩表,有很多表同時(shí)join。那么將會(huì)出現(xiàn)final stage之前將shuffle write M*N*K*P...? 無(wú)限擴(kuò)張的數(shù)據(jù)集。而且根本沒法優(yōu)化。
如下DAG:

本來(lái)只有百萬(wàn)級(jí)別的數(shù)據(jù)量,經(jīng)過(guò)cross join后 數(shù)據(jù)量達(dá)到百億千億級(jí)別。將耗費(fèi)大量時(shí)間去shuffle write,也會(huì)導(dǎo)致大量executor磁盤消耗。

剛開始可能會(huì)想如果將左表進(jìn)行collect操作? 先減少主表的數(shù)據(jù)量就會(huì)減少整個(gè)DAG的數(shù)據(jù)量。但是collect之后只能在map/foreach函數(shù)進(jìn)行接下來(lái)的操作。就會(huì)導(dǎo)致整個(gè)DAG產(chǎn)生大量的小job,能算了 但是特別慢而且不優(yōu)雅。
因?yàn)榻?jīng)過(guò)join多表才產(chǎn)生的cross join,那么不妨把多表進(jìn)行單獨(dú)的倆表join,就算產(chǎn)生cross join 數(shù)據(jù)量也是可控的。
但是spark的DAG是根據(jù)整體算子構(gòu)建最后的action算子才會(huì)觸發(fā)計(jì)算,那么無(wú)論何種方式進(jìn)行DAG構(gòu)建,最終還是會(huì)匯總到一起再計(jì)算。還是會(huì)產(chǎn)生多表cross join。
那么問(wèn)題就來(lái)到如何提前觸發(fā)倆表join的提前計(jì)算了。
眾所周知repartition可以觸發(fā)shuffle,但是shuffle只是改變分區(qū)數(shù),shuffle=提前計(jì)算嗎?
于是我就試了一試。果然。。。

repartition觸發(fā)了shuffle,相當(dāng)于觸發(fā)了提前計(jì)算。大大減少了數(shù)據(jù)量 而且最后還能以對(duì)等join進(jìn)行連接。