Cost-based query transformation in Oracle
Enhanced Subquery Optimizations in Oracle
Cost-based query transformation in Oracle
本文介紹Oracle的查詢優化框架,
先描述,Oracal分別在RBO和CBO做了哪些事情,為什么要這樣做
Heuristic Transformation
先看下RBO的部分,RBO部分的Rule基本都是確定可以帶來優化的
Subquery Unnesting
子查詢消除,子查詢如果用apply的方式的話,文中稱TIS,Tuple iteration semantics,基本等同於nested loop方式,比較低效
消除的方法分成兩大類,
1. 把子查詢 merge 到外部查詢里面去
如下面的例子,把exists變成semi-join
2. 產生inline views,或derived table的方式,這種方式會放到CBO里面,所以后面給出例子
Join Elimination
消除無用的Join
其中Q4,dept_id是foreign key,所以每個employee都必須有一個dept,這里join起不到filter的作用
Filter Predict Move Around
Filter下推,盡早的過濾數據,前提是這里的Filter是inexpensive的
Group Pruning
刪掉在外層查詢中不需要的group
下面的例子,在外層查詢中,過濾city,那么city其實就決定了state,country,子查詢中的group by 就沒有必要了
Cost-Based Transformations
這里講到重點,看下哪些Transformation應該在CBO里面去做的
Subquery Unnesting
第一個仍然是子查詢消除,前面說了,如果是產生inline view的方式,需要用CBO
下面的例子,從Q1到Q10,產生了inline view或派生表 V
這里產生inline view的方式不一定會比nested loop的方式更好,如果filter出的row很少,而索引建的很好,很可能nested loop的方式更優
所以這種不確定的情況下,需要CBO來判斷
Group-by and Distinct View Merging
右稱為,Groupby Pull-up,如果join會大幅降低數據量,那么把groupby上提是核算的,因為groupby一般都是聚合,比較expensive的操作
比如下面Q11的例子,
把計算平均salary的inline view,挪到了外部查詢的group by
可以看到把group by移到外面后,group by的field需要加上join key
Group-by Placement
對應於上面說的Pull Up,這里是Push Down
Join Predicate Pushdown
把外部查詢的join predicate下推到子查詢中,
一般套路都是uncorrelation,這里反之,不是所有情況都可以這樣下推
例子,
Join Factorization
將公共的 join tables 上提
Predicate Pullup
將Expensive的Predicate進行上提,
Set Operator Into Join
Disjunction Into Union All
Framework For Cost-based Transformation
State Space Search Tech
CBO有個關鍵的問題是,如果Transformation持續變多,那么搜索空間是成指數級別上升的
針對這樣的問題,比較可行的方式是引入隨機算法,
Oracle的搜索算法如下,
Exhaustive,窮盡法
Iterative,局部最優,每次選擇不同的初始點,有點像退火
Linear,動態回歸
Two-pass,強行降低搜索空間
然后這里比較有借鑒意義,針對不同的search規模,我們應該選用不同的搜索算法
Transformation執行的方式
Oracle中按照順序的方式去執行Transformations,
這里給出各個分類的執行順序
當然有些情況下光順序執行是不夠的,
3.3里面提到了,
Interleaving方式,有些rule需要交叉的執行
舉得例子是,Unnesting和View merging
Juxtaposition的方式,
Enhanced Subquery Optimizations in Oracle
本文討論Oracle對於子查詢的優化方法
Subquery Coalescing
子查詢合並,把多個子查詢合並成一個
這里提出,Container和Contained的概念
直觀上,如果A contain B
A and B,就可以remove A
A or B,就可以removeB
Coalescing Subqueries of The Same Type
SameType,類型一樣,要不都是Exist,要不都是Not Exist
和上面說的一致,只是這里加上Exist和Not Exist,有點繞
總之conjunction留小的,contained,disjunctive留大的,container
對於不滿足Containment Property的子查詢,仍然可能進行coalescing,
只要他們除了filter和predicates以外是equivalent的
這個很直觀,因為如果只是Predicate不一樣,是可以合並的
例子,雖然沒有containment關系,但是僅僅只有predict不一樣
可以看到,可以直接把Exists間的OR,轉化為predict之間的OR,很直覺
Coalescing Subqueries of Different Type
不同的Type,Exist和Not Exist之間的
可以看TPC-H的Q21,
兩個子查詢是滿足Containment關系的,但是類型不一樣
這里的感覺就要從Container中挖去Contained的那塊
是這樣轉換的,
用Having,對滿足條件的case求sum,然后過濾,好tricky
Coalescing and Other Transformations
Q5加上外層的Join就是Q6
這里做的轉換是,View merging,就是Groupby Pullup
但是GroupBy的Pull up還是Push down,需要通過cost-based來決定
Subquery Removal Using Window Functions
Oracle有窗口函數,可以用於替換子查詢,論文里說,對於TCP-H,性能會有10倍提升
這里有subsume的概念,outer query包含子查詢中的所有tables和predicates
這個例子,滿足Subsume關系,在子查詢中主要為了做AGG
所以這里用窗口函數就可以簡單的remove掉子查詢
Correlated Subsumed Subquery
相關子查詢,在TCP-H中的代表是Q2,Q17
Q2,子查詢中主要為了求min
用窗口函數,改造后
對於Q17,微軟提出的是SegmentApply的方案,這里用窗口函數改造后,
底下關於Duplicate rows,沒太懂
說是窗口函數必須within a view,沒看出和上面的區別
Uncorrelated Subsumed Subquery
非相關子查詢,TCP-H,Q15
用窗口函數轉化為,因為是非相關子查詢,所以OVER里面是空的,不需要PBY