【連載】關係型數據庫是如何工作的?(16) - 查詢管理器之Merge Join

歸併連接是唯一的生成排序結果的連接方式。其可以劃分爲兩步:

  1. 排序操作:對兩個輸入結果集按照連接字段排序;
  2. 歸併操作:歸併經過排序的結果集到一起。

排序

之前我們已經介紹過歸併排序,在這歸併排序是一個好的算法但不是最好的,如果內存足夠會有更好的算法。
有些場景下數據集已經經過了排序,例如:

  • 如果表示自然排序的,比如一張按照索引組織數據的表;
  • 如果連接條件中的關係是一個索引;
  • 如果連接一個查詢過程中已經排序過的中間結果。

歸併連接

歸併連接

這一步和我們之前介紹的歸併排序很相似。但是這次我們不用取出兩個關係的所有元素,只需取出相等的元素即可,下邊是其過程:

  • 1) 比較兩個關係中的當前元素(第一次比較就是其第一個元素);
  • 2) 如果兩個元素相等則將其放入結果集中,然後比較下一個元素;
  • 3) 如果不相等則將本次比較元素較小關係的指針移向下一個元素,另外一個關係指針不動。
  • 4) 重複1、2、3步,直到其中一個關係的指針到達最後一個元素。

因爲兩個關係時排過序的,所以無須將指針向前移動。這是一個簡化的算法,因爲它並沒有考慮相同元素出現多次的情況,否則它會複雜很多。

如果兩個關係已經排序,則歸併連接時間複雜度是O(N+M);否則是O(N*Log(N) + M*Log(M))。

下邊是一個考慮了相同元素出現多次情況的僞代碼(但我並不保證其實100%正確哦):

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

哪種join是最好的呢

好了,三種常見join方式我們都介紹完了,那麼哪種join是最好的呢?如果有最好的,那就沒必要存在3種join了。這個問題很難回答,因爲影響它的因素很多:

  • 空閒內存的大小:沒有足夠的內存,那就沒法使用強大的Hash Join;
  • 兩個數據集合的大小:如果是一個大表和一個小表,那麼nested loop join會比hash join更快,因爲構建hash表比較耗時;如果是兩個大表,則loop join會很耗CPU;
  • 索引:對於兩個B+Tree索引,最好使用merge join;
  • 如果結果集需要排序:即時是兩個沒有排序的數據集,爲了最終排序的結果也要使用merge join;
  • 如果關係已經排序:最佳選擇是merge join;
  • 連接類型:是相等條件(如: tableA.col1 = tableB.col2)?是內連接、外連接、全連接,還是自連接?有些連接在特定場景下效果不錯;
  • 數據的分佈情況:如果數據分佈比較集中,比如使用人的last name來連接(很多人的last name都是相同的),這時使用hash join很糟糕,因爲hash衝突會很嚴重;
  • 是否需要多進程或多線程執行連接操作。

如果想了解更多,請查閱DB2OrcaleSQL Server官方文檔。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章