分析執行計劃是解決ORACLE慢SQL的重要手段。獲取到ORACLE的執行計劃后,經驗豐富的DBA根據連接方式、訪問路徑等可能一眼就能看出性能問題在哪里;但新手DBA可能不清楚執行計劃該從哪里看,也不清楚執行計劃的順序是什么。所以這篇文章想盡可能的說清楚怎么看ORACLE執行計劃順序。
Table of Contents
1.執行計劃樣例
這里有一個執行計劃樣例,下文所有的講解都是基于如下執行計劃進行的。可以先看一下,先嘗試自己進行排序。首先說明的是Id列數字并不是執行計劃的順序號。

2.基礎知識了解
2.1.父子兄弟節點
Oracle的執行計劃是樹形結構,執行順序類似于二叉樹。理解執行計劃中的父節點、子節點、兄節點、弟節點是至關重要的。
2.1.1.父子節點

可以根據執行計劃縮進來判斷父子節點。如上圖所示,可以看到一條紅色箭頭,下面用Id號來代替Operation步驟。
1 比 0 縮進一格,且 0 在上方;則 1 是 0 的子節點,0 是 1 的父節點。
2 比 1 縮進一格,且 1 在上方;則 2 是 1 的子節點,1 是 2 的父節點。
以此類推…
10 比 9 縮進一格,且 9 在上方;則 10 是 9 的子節點,9 是 10 的父節點。
10 比 11 縮進一格,且 11 在下方,10 在上方,則 10 與 11 無父子關系。
也可以說 10 與 11 無任何關系,唯一的關系就是在同一個樹形結構上。
2.1.2.兄弟節點

同樣,可以根據執行計劃的縮進來判斷兄弟節點。如上圖所示,可以看到4條紅色箭頭,下面用Id號來代替Operation步驟。
9 與 11 縮進相同,9在上,11在下;則9是兄節點,11是弟節點。
8 與 12 縮進相同,8在上,12在下;則8是兄節點,12是弟節點。
7 與 13 縮進相同,7在上,13在下;則7是兄節點,13是弟節點。
6 與 15 縮進相同,6在上,15在下;則6是兄節點,15是弟節點。
新手可能會有疑問:為什么上文中的 14 與 8、12縮進相同,但卻不是兄弟節點呢?
這是因為13在14上方,14比13縮進一格,所以14是13的子節點,與8、12沒有兄弟關系。
2.2.深度
這里的深度就是上文提到的縮進,代表著執行計劃某一個步驟的深度。
例如上文描述的 Id 為5的步驟,相比與 Id 為0的步驟有5個縮進,其深度就是5;這也代表著此步驟有5層父步驟(Id為4、3、2、1、0)。
可以通過下面的SQL查看執行計劃步驟的深度值。其中id是執行計劃中的Id號,parent_id是其父節點的Id號,depth就是深度值。
select
sp.id
sp.parent_id,
sp.depth,
sp.operation|| '' || sp.options as operation,
sp.object_name
from v$sql_plan sp
where sp.sql_id = 'xxxx'
2.3.position
position代表擁有相同父節點的兄弟節點執行順序。
在樹形結構中,樹中每個級別最左的葉節點最先執行。結合起來理解是在樹形結構中左為兄、右為弟,在執行計劃列表中上為兄、下為弟。
可以用下面的SQL查詢執行計劃的position。
select
sp.id
sp.parent_id,
sp.depth,
sp.postion,
sp.operation|| '' || sp.options as operation,
sp.object_name
from v$sql_plan sp
where sp.sql_id = 'xxxx'
SQL輸出結果如下圖。可以發現Id為9和Id為11的步驟擁有相同的父節點8,且深度相同;其中Id為9的position值是1,Id為11的position值是2,這表示Id為9的步驟先于Id為11的步驟執行。

這體現在樹形結構中,Id為9的步驟是左節點,Id為11的步驟是右節點;體現在執行計劃列表中則是Id為9的步驟在上,Id為11的步驟在下(這一點大家在前文中的執行計劃列表截圖中可以看得出)。
3.樹形結構轉換
前文講了很多次樹形結構,但新手可能對此并不了解,腦海中無法形成概念。我自己早些時候也是查了很多資料去理解數據結構中的樹,所以在這里和大家分享將執行計劃轉換成樹形結構去加深理解。
執行計劃轉換成樹形結構過程拆解。
(1)拆解步驟1
前文已知執行計劃每個步驟的深度,其中最深的是Id=10的步驟(這也是執行計劃的入口)。
前文已知 10 的父節點是9,9的弟節點是11,左為兄、右為弟。
前文已知9與11的父節點是8。
所以,此時樹形圖如下:

(2)拆解步驟2
8與12是兄弟節點,8為兄、12為弟,左為兄、右為弟。
8與12的父節點是7。
所以,此時樹形圖如下:

(3)拆解步驟3
7與13是兄弟節點,7為兄、13為弟,左為兄、右為弟。
7與13的父節點是6。
所以,此時樹形圖如下所示:

(4)拆解步驟4
6與15是兄弟節點,6為兄、15為弟,左為兄、右為弟。
6與15的父節點是5。
13是14的父節點。
所以,此時樹形圖如下所示:

(5)拆解步驟5
Id為0、1、2、3、4依次為后一位的父節點,0是根節點。
所以最終的樹形結構如下所示:

(6)樹形結構總結
到第(5)步,這個執行計劃的完整樹形結構已經呈現出來了。這里再總結下根據樹形結構如何查看執行順序,也就是數據結構中的樹形順序。
① 從頂部開始
② 在樹形結構中向左下移動,直至達到左節點(再也沒有子節點的左節點);首先執行此節點。

③ 查看此節點(首先執行的節點)有無同級節點,也就是弟節點;有則執行弟節點。
9有其同級弟節點11,所以執行11。
④ 執行完這兩個節點,再向上執行它們的父節點。
執行完11后,9與11的父節點是8,所以執行8。
此時執行順序是 10->9->11->8
⑤ 完成這一組父子節點后,在樹形結構中,向上退一級,查看上退后這一組的父子節點,先左子節點,再右子節點,最后父節點。
按照前文描述規律依次執行。
需要注意的是14優先于13執行,因為14是13的子節點。如果某節點有子節點,則先執行子節點;如果有兩個同級子節點,則先執行左子節點。
此時的執行順序是 10->9->11->8->12->7->14->13->6
⑥ 在樹形結構中依照此邏輯不斷上移,直至根節點。
最終的執行順序是 10->9->11->8->12->7->14->13->6->15->5->4->3->2->1->0
4.實戰技巧
在工作中進行SQL優化時,分析執行計劃肯定不可能像前文一樣查父節點、深度、position,然后再畫個樹形結構圖。沒有這么多時間,客戶也沒耐心等。前文的描述都只是為了加深理解。
在工作中應該怎么快速理清楚執行計劃順序呢?
分享一種我經常用的方法。
(1)利用截圖工具的箭頭找到執行計劃入口

(2)看入口步驟有沒有弟節點,再看弟節點有沒有子節點
如果有弟節點,弟節點無子節點,那么第二步就是該弟節點。
如果有弟節點,弟節點有子節點,那么第二步就是從該弟節點開始用第Ⅰ步中箭頭方式,找到它的沒有子節點的節點。
像我們這個執行計劃,入口沒有弟節點。那么,就往上找它的父節點,即9,第二步執行9。
(3)拉長箭頭找對應的兄弟節點
找到執行計劃的入口后,沒有弟節點,就往上走(上為父)。根據前文描述:先弟節點,弟節點執行完了,執行父節點。
且執行計劃用肉眼直接去看兄弟節點,很容易看錯的。所以可以借助截圖工具中的箭頭拉長,看兩個步驟是否有相同的縮進。比對后相同縮進的步驟就是兄弟節點,上為兄,下為弟;兄先于弟執行。
對于這個例子而言,執行完9,通過箭頭發現,11是它的弟節點,所以下一步執行11。
執行完11,執行9和11的父節點8,執行完8,通過箭頭發現12是8的弟節點,所以下一步執行12。
以此類推,就可以得出執行順序了。
10->9->11->8->12->7->14->13->6->15->5->4->3->2->1->0

這種方法適合剛開始接觸執行計劃的新手DBA使用,如果經常看執行計劃,這種方法很快也可以拋棄了,因為肉眼就可以大致判斷出執行計劃順序了。




