1. 概要
join是sql語言中常用的操作,一般用於建立多表之間的連線關係。spark sql有兩類(三種)join的實現,每種join的實現方式都有各自不同的應用場景。
hash join實現原理
先來看看這樣一條sql語句:select * from order,item where item.id = order.i_id,參與join的兩張表是order和item,join key分別是item.id以及order.i_id。現在假設join採用的是hash join演算法,整個過程會經歷三步:
確定build table以及probe table:這個概念比較重要,build table會被構建成以join key為key的hash table,而probe table使用join key在這張hash table表中尋找符合條件的行,然後進行join鏈結。build表和probe表是spark決定的。通常情況下,小表會被作為build table,較大的表會被作為probe table。
構建hash table:依次讀取build table(item)的資料,對於每一條資料根據join key(item.id)進行hash,hash到對應的bucket中(類似於hashmap的原理),最後會生成一張hashtable,hashtable會快取在記憶體中,如果記憶體放不下會dump到磁碟中。
匹配:生成hash table後,在依次掃瞄probe table(order)的資料,使用相同的hash函式在hash table中尋找hash(join key)相同的值,如果匹配成功就將兩者join在一起。
hash join效能如何?很顯然,hash join基本都只掃瞄兩表一次,可以認為是o(a + b),較之最極端的是笛卡爾積運算o(a * b)。
為什麼build table選擇小表?道理很簡單,因為構建hash table時,最好可以把資料全部載入到記憶體中,這也決定了hash join只適合於一張表較小的場景,如果是兩個較大表的場景就不適用了。
上文的hash join是傳統資料庫中的單機join演算法,為了盡可能利用分布式計算資源進行平行計算,提高總體效率,在分布式環境下需要經過一定的改造。hash join分布式實現有broadcast hash join和shuffle hash join兩種方案:
broadcast hash join
broadcast hash join可以分為兩步:
broadcast階段:將小表廣播到所有的executor上,廣播的演算法有很多,最簡單的是先發給driver,driver再統一分發給所有的executor,或者就是基於bt的p2p思路。
hash join階段:在每個executor上執行hash join,小表構建為hash table,大表的分割槽資料匹配hash table中的資料;
broadcast hash join有以下幾個條件:
被廣播的表大小需要小於spark.sql.autobroadcastjointhreshold的值,預設是10m;
基表不能被廣播,比如left outer join時只能廣播右表。
broadcast hash join的缺點也是比較明顯的,即只能廣播較小的表,否則資料的冗餘傳輸會遠大於shuffle的開銷。另外被廣播的表在每個executor上都會儲存乙份,這會對executor的記憶體造成一定的壓力。
shuffle hash join
shuffle hash join分為兩步:
對兩張表分別按照join key進行shuffle,那麼相同的key一定會落到相同的分割槽。
對應分割槽中的資料進行join,先將小表分割槽構建為乙個hash表,然後根據大表中記錄的join key的hash值拿來進行匹配,即每個節點單獨執行hash演算法。
hash join方式只對於兩張表中有一張是小表的情況適用,但當兩個表都非常大時則不適合。這是因為join時生成的join key會非常大,不能將資料完全載入到記憶體中。為了應對大表join的場景,sparksql提供了一種全新的方案sort merge join。
sort merge join首先將兩張表按照join key進行重新shuffle,保證join key值相同的記錄會被分在相應的分割槽,分割槽後對每個分區內的資料進行排序,排序後再對相應的分區內的記錄進行連線。可以看出,無論分割槽有多大,sort merge join都不用把一側的資料全部載入到記憶體中,因為兩個序列都是有序的,此時從頭遍歷,碰到key相同的就輸出,如果不同,左邊小就繼續取左邊,反之取右邊。
整個過程分為三個步驟:
shuffle階段:將兩張大表根據join key進行重新分割槽。
sort階段:對單個分割槽節點的兩表資料,分別進行排序;
merge階段:對排好序的兩張分割槽表資料執行join操作。join操作很簡單,分別遍歷兩個有序序列,碰到相同join key就merge輸出,否則取更小一邊,見下圖示意:
ConcurrentHashMap實現原理
concurrenthashmap實現原理 在jdk1.7中 concurrenthashmap是通過segment陣列 hashentry陣列 單鏈表的結構進行儲存資料。segment陣列中存放的是hashentry陣列的首位址,hashentry中存放的是乙個單鏈表 首節點位址 put 我們通過...
ConcurrentHashMap 實現原理
由於hashmap是乙個執行緒不安全的容器,主要體現在容量大於總量 負載因子發生擴容時會出現環形鍊錶從而導致死迴圈。因此需要支援執行緒安全的併發容器concurrenthashmap。如圖所示,是由segment陣列 hashentry陣列組成,和hashmap一樣,仍然是陣列加鍊表組成。concu...
iOS NSDictionary 字典 實現原理
1.nsdictionary 字典 是使用 hash表來實現key和value之間的對映和儲存的,hash函式設計的好壞影響著資料的查詢訪問效率。void setobject id anobject forkey id akey 2.objective c 中的字典 nsdictionary 底層其...