天天看點

資料庫的表連接配接方式詳解

資料庫的連接配接方式:

Nested loop join

Hash join

Merge join

Nested loop join:

資料庫的表連接配接方式詳解

Nested loop join的思路:

将Outer relation的每一行資料和Inner relation的每一行做對比,如果符合關聯條件的話才會傳回關聯的資料集。

僞代碼:

nested_loop_join(array outer, array inner)
  for each row a in outer
    for each row b in inner
      if (match_join_condition(a,b))
        write_result_in_output(a,b)
      end if
    end for
   end for
           

是以這是一個兩層的循環,它的算法時間複雜度是 O(N*M)。

根據磁盤的I/O,Outer relation有N行資料,Inner relation有M行資料。那麼根據這個算法就需要從磁盤上讀N+N*M行資料。但是如果Inner relation的資料量足夠小可以存在記憶體裡面,那麼磁盤的I/O就隻有N+M了。

總結:

如果Inner relation小的話比較合适使用這樣方式。

合理的在關聯字段上面建索引也能減少I/O。

Hash join:

Hash join的算法實作比Nested loop會更加複雜,但是更多的情況下面消耗更小成本。

資料庫的表連接配接方式詳解

Hash join的思路:

1、從Inner relation取出所有的元素

2、将取出的元素在記憶體裡建立哈希表

3、從outer relation一行一行的取出所有的元素

4、計算從outer relation取出的元素的哈希值,跟據哈希值去找到哈希表裡面想對應的桶

5、然後在桶裡面再找是否有比對元素

桶(bucket)

在算法時間複雜度方面我們作出下面的假設:

1、Inner relation的元素分别放到了X個桶裡

2、哈希值是均衡的,是以桶裡面的資料應該也是相當的

3、outer relation需要到桶裡面比對到一個元素

是以算法的時間複雜度是

(M/X) * N + cost_to_create_hash_table(M) + cost_of_hash_function*N

Merge join:

Merge join的實作思路:

Merge join沒有區分Inner table或者Outer table,對于兩個資料集都用了相同的規則去處理。

1、将兩個資料集都按關聯join的條件排序

2、将兩個排序好的資料集歸并到一起

資料庫的表連接配接方式詳解

Merge join僞碼:

mergeJoin(relation a, relation b)
  relation output
  integer a_key:=0;
  integer b_key:=0;
 
  while (a[a_key]!=null or b[b_key]!=null)
    if (a[a_key] < b[b_key])
      a_key++;
    else if (a[a_key] > b[b_key])
      b_key++;
    else //Join predicate satisfied
	//i.e. a[a_key] == b[b_key]

      //count the number of duplicates in relation a
      integer nb_dup_in_a = 1:
      while (a[a_key]==a[a_key+nb_dup_in_a])
        nb_dup_in_a++;
		
      //count the number of duplicates in relation b
      integer dup_in_b = 1:
      while (b[b_key]==b[b_key+nb_dup_in_b])
        nb_dup_in_b++;
		
	  //write the duplicates in output
	   for (int i = 0 ; i< nb_dup_in_a ; i++)
	     for (int j = 0 ; i< nb_dup_in_b ; i++)	   
	       write_result_in_output(a[a_key+i],b[b_key+j])
		   
      a_key=a_key + nb_dup_in_a-1;
      b_key=b_key + nb_dup_in_b-1;

    end if
  end while
           

怎麼選擇合适的算法:

    如果沒有足夠的記憶體就不要考慮hash join(或者說是full in-memory的hash join)

    兩個不同size的資料集,如果一個資料集大一個資料集很小,使用nested loop會比hash join達到更高的效率,如果是兩個都很大的資料集使用nested loop的話會需要更多的cpu和磁盤開銷。

   如果存在索引的話,如果關聯條件上面有B+ Tree的話就可以考慮是用merge join

   如果你需要排序好的資料集,那麼你也可以使用merge join,因為merge join的結果集就是一個排序後的結果。