Database | 淺談Query Optimization (2)

爲何選擇左深鏈接樹

對於n個表的鏈接,數量爲卡特蘭數,近似\(4^n\),所以爲了減小枚舉空間,早期的優化器僅考慮左深鏈接樹,將數量減小爲\(n!\)html

但爲何是左深鏈接樹,而不是其餘樣式呢?node

若是join算法爲index join或者hash join,當兩張表進行鏈接的時候,須要爲左表創建哈希映射或者搜索索引,鏈接時直接尋找對應的元素:算法

join ⋈2 必須等到⋈1 的所有元組輸出以後才能生成它的映射表/索引。即只有⋈1 結束後,⋈2才能開始輸出元組。而此時⋈3必須等待,直到⋈2完成。oop

對於多個表的鏈接,當⋈i正在執行時,⋈i+1處於半活躍的狀態,它累積⋈i的輸出到緩衝區並創建映射,然後面的⋈i+2⋈n均處於空閒狀態。優化

當執行鏈接⋈1時,須要爲⋈1中的表分配內存,而後將輸出的元組一樣儲存在內存中。而如前所述,只有⋈1結束時⋈2才能開始,所以⋈1結束時能夠直接釋放掉以前佔用的內存空間。spa

而對於其餘形式的樹,例如右深鏈接樹,由於左側的操做數都是一個關係,全部的join鏈接符均可覺得左表創建映射表/索引,會佔用大量的內存空間。.net

所以對於Hash Join,採用左深鏈接樹能夠減小執行計劃對內存的需求。code

當join算法爲nested-loop join時,若是採用右深鏈接樹,結果會更糟糕:htm

image

如圖,執行⋈3時會致使屢次訪問⋈3的第二個操做數,使得該子查詢屢次執行,會屢次訪問表T、R、S增長讀取磁盤的次數。blog

尋找最佳鏈接順序

最佳的鏈接順序便是中間結果中產生最少元組數量的鏈接順序

由於不一樣的鏈接順序都會訪問每一個表一次,而錶鏈接的中間結果每每須要寫入磁盤中暫時儲存,所以中間結果元組數量越少,讀取磁盤次數越少。

所以咱們定義 cost for join 便是指鏈接後產生的中間結果的個數。

而不去鏈接怎麼知道中間結果的個數呢?那就須要用到上一篇博客中提到的謂詞的選擇性數據直方圖,估算鏈接後產生的元組個數。

對於三個關係的鏈接,須要維護以下的數據圖:

首先是相互鏈接關係的列表,而後是鏈接後的元組總數和鏈接的cost,以及這幾個關係的最佳鏈接順序。

而後對給定的n個表,將其分解成n個n-1的表的鏈接,再逐層分解,先求得兩個關係的最佳鏈接方式。最優解便是這些子問題的組合。

算法的僞代碼以下:

j = set of join nodes
 for (i in 1...|j|):    //一開始尋找單個join的最佳方案,再向上延伸
     for s in {all length i subsets of j}   //尋找s的最優鏈接
       bestPlan = {}
       //i-1的最優解都已經儲存在optjoin中
       //只須要考慮再加一個表的狀況
       for ss in {all length i-1 subsets of s}   
            subplan = optjoin(ss) 
            //optjoin 能夠理解爲一個哈希表,儲存對應ss的最優鏈接
            plan = best way to join (s-ss) to subplan
            if (cost(plan) < cost(bestPlan))
               bestPlan = plan
      optjoin(s) = bestPlan
 return optjoin(j)

具體而言,假設如今是R、S、T、U四個關係相鏈接,咱們已經得出兩個關係的最優解以下圖所示:

那麼假設如今有

i=3, s=R,S,T
//那麼對於ss
ss=R,S or R,T or S,T

計算出三種s的cost,找出bestplan,則

optjoin(R,S,T) = bestplan

咱們先不考慮謂詞選擇性,直接將生成的元組個數做爲cost,那麼

由於 T(S ⋈ T) = 2000, 所以 {S, T} ⋈ R 即爲 s=R, S, T 的最優順序。

將length(s)=3的四種狀況依次計算,再求得四個關係相鏈接的最優順序。

動態規劃算法的缺點

  1. 缺少擴展性:當須要加入新的join方法時,須要修改大量代碼。若是增長新的operator,好比aggregation,那麼修改就更加困難。
  2. 對Join順序優化的問題很是適合,可是卻不容易適用其餘的優化方法,好比對GroupBy或者Union的優化。

動態規劃的主要意義仍是尋找次優的鏈接順序,而且其搜索空間依然很大,須要\(O(n*2^{n-1})\),當表的數量爲兩位數時依然須要較長時間來響應。

參考

Trafodion優化器簡述

left deep tree

dyn-prog-join

相關文章
相關標籤/搜索