- Overview
- Nested Loop Join
- Naïve
- Block
- Index
- Sort-Merge Join
- Hash Join
- Simple Hash Join
- Partition Hash Join
- 總結
Overview
輸出形式:早物化與晚物化(OLAP一般都是晚物化)
代價分析:一般用IO次數計算(最終結果可能落盤,也可能不落盤,所以我們只計算輸出結果之前的IO次數)。
Join左邊稱為外表(Outer Table),右邊稱為內表(Inner Join),外表一般是小表。
Nested Loop Join
Naïve
前提:緩衝區大小為3,一個外表輸入,一個內表輸入,一個輸出。
基本思想:雙重迴圈,對每一個元組(Tuple)進行配對,讀取S表m次。
Cost:\(M+(m*N)\)
Block
前提:緩衝區大小為3,一個外表輸入,一個內表輸入,一個輸出。
基本思想:雙重迴圈,對每一個塊(Block,同頁Page)內進行配對,所以讀取S表M次。
Cost:\(M+(M*N)\)
如果緩衝區容量為B,即可以容納B個塊(頁),B-2個塊用於外表輸入,一個塊用於內表輸入,一個塊用於輸出。
Cost:\(M+(⌈M/(B-2)⌉*N)\)
Index
前提:緩衝區大小為3,一個外表輸入,一個內表輸入,一個輸出。
基本思想:如果外部表有索引,那麼內層迴圈無需遍歷,查詢索引即可。
Cost:\(M+(m*C)\)
Sort-Merge Join
基本思想:排序後的序列更容易找到匹配項。
分為兩個步驟:
- 排序:用任意排序方式,將R和S排序。
- 合併:移動兩個指標尋找匹配項,過程中可能需要回退指標。
這兩個步驟和上一節提到的外部歸併排序思想相同,但不是同一個東西。
SortCost(R):\(2M*(1 + ⌈ log_{B-1} ⌈M / B⌉ ⌉)\)
SortCost(S):\(2N*(1 + ⌈ log_{B-1} ⌈N / B⌉ ⌉)\)
MergeCost:\(M+N\)
Total Cost:Sort + Merge
當R中存的是相同元素,且S中也是時,指標需要一直回退,Sort-Merge Join退化為Nest Loop Join。
Hash Join
Simple Hash Join
基本思想:匹配項會被對映到同一個雜湊桶。
分為兩步驟:
- 構建雜湊表:對R表採用雜湊函式\(h_1\)進行雜湊,得到雜湊表,包含不同的雜湊桶(可以採用不同的雜湊表,但是鏈式雜湊最符合需求)。
- 探測:把S表元組用雜湊函式\(h_1\)進行雜湊,得到對應的雜湊桶位置,然後在雜湊桶中尋找匹配項。
最佳化措施:布隆過濾器。
建立雜湊表時順帶構建布隆過濾器,探測階段先走布隆過濾器再走雜湊桶。
存在的問題i:該演算法需要保證雜湊表能存在記憶體中,如果雜湊表太大導致無法存到記憶體中,需要不斷地換入換出,影響效率。但不幸的是,大部分情況下,我們都不能保證記憶體能完全存下雜湊表。
Partition Hash Join
基本思想:把兩個表分別用同一個雜湊函式雜湊,相同雜湊桶之間進行配對,如果雜湊桶都存不下,就再雜湊一次,直到能存下為止。
讀取對應的雜湊桶到記憶體中配對即可。
Partition Cost:\(2(M+N)\) 【讀取資料+雜湊桶落盤(雜湊空間複雜度為\(O(n)\))】
Probe Cost:\(M+N\)
Total Cost:\(3(M+N)\)
總結
Algorithm | IO Cost | Example |
---|---|---|
Naïve Nested Loop Join | M + (m * N) | 1.3 hours |
Block Nested Loop Join | M + (⌈M / (B-2)⌉ * N) | 0.55 seconds |
Index Nested Loop Join | M + (m * C) | Variable |
Sort-Merge Join | M + N + sort cost | 0.75 seconds |
Hash Join | 3 * (M + N) | 0.45 seconds |
結論:選擇Partition Hash Join,出現下述情況時使用Sort-Merge Join:
-
資料偏斜嚴重:Hash Join退化為Sort-Merge Join
-
資料本身需要被排序:此時Sort-Merge Join只需要額外付出 \(M+N\) 即可實現Join
一般資料庫中,Hash Join和Sort-Merge Join都會實現。