CMU Database Systems - Query Optimization

查詢優化應該是數據庫領域最難的topic算法

當前查詢優化,主要有兩種思路,sql

Rules-based,基於先驗知識,用if-else把優化邏輯寫死數據庫

Cost-based,試圖去評估各個查詢計劃的cost,選取cost比較小的oop

一個sql query的處理流程,優化

先是Parser,生成抽象語法樹ast,Binder會去作元數據對應,把parse出來的name對應到數據庫中的結構,表,字段等ui

而後Rewriter就是Rules-based的改寫,而Optimizer是cost-based的優化spa

 

Relational Algebra Equivalences

作查詢優化的前提是,查詢的結果是不能變的3d

不管你查詢怎麼優化,最終獲得的結果是同樣的,那麼就稱他們是,關係代數等價blog

對於不一樣的operator,有些通用的優化rules,索引

這裏給些例子,

Selections

對於selection,儘可能下推,謂詞下推,儘可能早作

 

Projections

projection也是應該儘早去作,不須要的字段就根本不用讀出來

 

Joins

對於Join是符合交換律和結合律的,可是對於多表join,你須要嘗試的可能性是很是多的

 

Cost Estimation

cost-based的查詢優化,關鍵就是要可以知道cost

如何預估cost是很複雜的問題

當前的思路,就是咱們會事先對數據表,列,索引作些統計,並存儲到catalog裏面,而後後面就根據這些統計數據來預估cost

主要的統計數據,包含兩項,行數和每一列的distinct values的個數

而後有個概念,selection cardinality,兩個相除,就是平均每一個value多少行

這裏的假設是數據是均勻分佈,很naive

 

有了這些概念,咱們就能夠來定義複雜謂詞,操做,的selectivity,篩選率

 

Equality,Range

Equality的定義有些confuse,SC(P),SC(age=2)啥意思?

其實以range的邏輯看,這裏就應該是,A列一共有5個值,當前Equality只取其中一個,因此五分之一,就這麼簡單

 Conjunction和Disjunction

Join,對於join,這個cost算的很粗糙,好比R表中的行數 * 每行在S中的cardinality 

 

平均分佈問題

當前算cost,都是假設平均分佈,這個明顯是很不合理的

可是若是對於每一個value都去記錄一個統計,明顯不可行,太多了

因此有以下幾種近似方法,

一種,每一個value bucket都去統計太多,那就分組,這樣每一個組記錄一個統計,組內仍然假設平均分佈
分組能夠有兩種方式,第一個是固定bucket數,或者固定組內bucket統計和差很少,叫等寬

還有種更直接的方式,sampling

 

Query Optimization

上面說的cost estimation的方法都很naive,可是若是咱們能準確的預估執行計劃的cost,那麼如何真正的作查詢優化?

這裏分爲三種狀況,

Single Relation,Multiple relations, Nested Sub-queries 

Single Relation,比較簡單,單關係表的查詢
因此關鍵就是選擇合理的access method,是順序掃描,仍是用各類索引
這裏有個概念,sargable,數據庫專有概念,意思是查詢或執行計劃能夠用索引來優化的
OLTP的查詢每每都是sargable的,因此經過簡單的啓發式的方式就能夠找到優化方法

 

Multiple relations

多關係表join就比較複雜了 

除了要選擇各個表的access method

還須要選擇各個表的join順序和join算法

其中選擇join順序是個cost很高的事情,由於可能性和search space會比較的大

這裏介紹IBM R的方法,它把join順序簡化成,只考慮Left-deep tree(右圖最左邊這個)

這樣search space會大幅縮小,另外特地選擇left-deep tree的緣由是,這種join結構,比較容易pipeline執行,好比下圖,a b的join結果直接能夠用於和c join,當中間結果不是很大的時候,不須要不斷地的把結果寫到磁盤

 

對於Multiple relations,能夠嘗試用動態規劃來選擇best plan

 

更爲形象的例子來講明如何逐步篩選plan

第一步是選擇join的順序,能夠首先把明顯低效的,好比作cross-products的Prune掉
而後根據cost model找出best的plan

 第二步是選擇join算法,這裏有Nested Loop和Hash Join

 第三步是選擇access method,

 

Nested Sub-queries

第三種更爲複雜一些,在有子SQL的時候,如何優化?

有兩種方式,一種是經過rewrite,把嵌套的子語句flatten掉,如右圖的例子

另外一種方法,是decompose,以下面的例子

子句是要獲取最大的rating,這個反覆去執行必定是低效的,因此,乾脆把這個語句拿出來單獨執行,結果放在臨時表,而後執行主語句的時候把值填回去

相關文章
相關標籤/搜索