往期內容:
(Oracle)SQL優化基礎(一):獲取執行計劃
(Oracle)SQL優化基礎(二):統計信息
獲取到執行計劃后,對于新手朋友來講可能不知道該從哪看起;這篇文章就旨在可以幫助大家先從看懂執行計劃順序開始。
目錄
執行計劃
基本知識必備
Ⅰ:父子兄弟節點
Ⅱ:深度?
?Ⅲ:position
?轉化成樹形結構
實戰技巧
執行計劃
有如下執行計劃,該執行計劃是通過?DISPLAY_CURSOR 方法獲取的。后面所有的講解都會圍繞該執行計劃進行,大家也可以自己先嘗試進行排序。但首先要說明的是:Id列數字并不是執行計劃的順序號。
基本知識必備
Ⅰ:父子兄弟節點
Oracle的執行計劃是樹形結構,執行順序有點類似于二叉樹的邏輯。理解執行計劃中的父節點、子節點、兄節點、弟節點就很重要。
- 父節點與子節點
我們可以根據執行計劃縮進來判斷父子節點;如上圖所示,可以看到一條紅色箭頭,下面用 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 無任何關系,唯一的關系就是在同一個樹形結構上。
- 兄節點與弟節點?
同樣,根據執行計劃的縮進來判斷兄弟節點,如上圖所示,可以看到 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沒有兄弟關系。?
Ⅱ:深度?
這里的深度就是上文提到的縮進,代表著執行計劃某一個步驟的深度。上文為了容易理解用 “一格縮進” 來表示,但其實官方描述是深度。比方說上文的Id為5的步驟,相比于?Id為0的步驟有5個縮進,其深度就是5,也就代表著此步驟有5層父步驟(Id為4、3、2、1、0)。
總結來講就是:執行計劃的縮進層數代表了深度。
可以通過下面的SQL查看執行計劃步驟的具體深度值:
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'
結果如下,其中的depth列就是深度,id是執行計劃中的id號,parent_id是父節點的id號。
?Ⅲ: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'
執行結果如下圖所示,可以發現 Id 為9和11的步驟擁有相同的父節點8,深度相同,是兄弟節點;其中9的position值是1,11的position值是2,表示步驟9先于步驟11執行?。體現在樹形結構中,9為左節點,11為右節點;體現在執行計劃列表中即9在上,11在下(這點大家也可以在上面的執行計劃圖中看出來)。
這也可以得出來一個結論:兄先于弟執行,左先于右執行(同一層級)。
?轉化成樹形結構
執行計劃是按照樹形結構的順序執行的,將執行計劃轉化成樹形結構更容易幫助理解執行計劃順序。如果您對數據結構很有研究,那么執行計劃樹形圖對于您來講就太簡單了。如果您不熟悉,也沒關系,請您認真看我下面的步驟。
Ⅰ:
前面我們已經知道了執行計劃每個步驟的深度,其中最深的是10也就是執行計劃的入口。
由前面的知識,我們知道10的父節點是9,9的弟節點是11,左為兄,右為弟。
而9與11的父節點是8。
所以此時樹形圖如下所示:
Ⅱ:
8與12是兄弟節點,8為兄,12是弟;兄在左,弟在右。
8與12的父節點是7.
所以此時的樹形圖如下所示:
Ⅲ:
7與13是兄弟節點,7為兄,13為弟;兄在左,弟在右。
7與13的父節點是6.
所以此時的樹形圖如下所示:
Ⅳ:
6與15是兄弟節點,6為兄,15為弟;兄在左,弟在右。
6與15的父節點是5.
且13是14的父節點。
所以此時的樹形圖如下所示:
Ⅴ:
0、1、2、3、4、5依次為后一位的父節點,且0是根節點。
所以最終的樹形結構如下所示
【那啥,processon會員到期了,用的畫圖板,手殘,大家將就著看吧,不好意思哈😅】

其實講到這里可能已經有朋友將執行計劃的執行順序推測出來了。但我在這里還是講下根據樹形結構如何查看執行順序:
- 從頂部開始
- 在樹中向左下移動,直至到達左節點(沒有子節點的節點);首先執行此節點。
- 查看此節點(首先執行節點)有無同級節點,也就是弟節點;有則執行弟節點
- 執行完這倆節點后,執行它倆的父節點。
- 完成此組父子節點后,在樹中向上退一級,查看上退后這一組的父子節點,先左子節點后右子節點,最后父節點。
- 在樹中不斷上移,直至根節點。
以我們上面的樹形結構為例:
1、從頂部開始,最左節點是10
2、查看此節點(首先執行節點)有無同級節點,也就是弟節點;有則執行弟節點
9有其同級弟節點11,繼而執行11
3、執行完這倆節點后,執行它倆的父節點
執行完11后向上遞歸執行父節點8?
此時執行順序是【10 -> 9 -> 11 -> 8】
3、完成此組父子節點后,在樹中向上退一級,查看上退后這一組的父子節點,先左子節點后右子節點,最后父節點
按照上述的規律依次執行
但有一點需要提醒:
節點14是先于節點13執行的哦,因為14是13的子節點;如果某節點有子節點,則先執行子節點;如果有兩個同級子節點,先執行左子節點。
此時的執行順序是【10 -> 9 -> 11 -> 8 -> 12 -> 7 -> 14 -13 -> 6】
4、在樹中不斷上移,直至根節點
最終執行順序是【10 -> 9 -> 11 -> 8 -> 12 -> 7 -> 14 -13 -> 6 -> 15 -> 5 -> 4 -> 3 -> 2 ->1 -> 0】
實戰技巧
為了避免大家看到這里的時候,還得上翻執行計劃,我把執行計劃的圖再放一次。
?在工作中進行SQL優化時,想查看執行計劃順序肯定不能還查下v$sql_plan里的父節點、深度、position等值,然后再畫個樹形圖,這太二了。上面講了那么多,是為了幫新手朋友理解執行計劃順序的背景,也只有理解好了才能更好更快的讀懂執行計劃。
那么實戰中怎么看呢?我會利用截圖工具,不用啥牛逼的截圖工具,就QQ截圖就挺好用的!
Ⅰ:利用截圖工具的箭頭找到執行計劃入口,也就是執行順序第一步。
從Id=0這一步開始,一直向下向右移動,直到找到沒有子節點的步驟,就是執行計劃的入口。
如下圖:10就是入口。
Ⅱ:看下入口步驟有沒有弟節點,再看弟節點有沒有子節點
如果有弟節點,弟節點無子節點,那么第二步就是該弟節點。
如果有弟節點,弟節點有子節點,那么第二步就是從該弟節點開始用第Ⅰ步中箭頭方式,找到它的沒有子節點的節點。
像我們這個執行計劃,入口沒有弟節點。那么,就往上找它的父節點,即9,第二步執行9。
Ⅲ:把箭頭拉長找對應的兄弟節點
找到執行計劃的入口后,沒有弟節點,就往上走(上為父)。然后記住我們前面的知識:先弟節點,弟節點執行完了,執行父節點。
且執行計劃用肉眼直接去看兄弟節點,很容易看錯的。所以可以借助截圖工具中的箭頭拉長,看兩個步驟是否有相同的縮進。比對后相同縮進的步驟就是兄弟節點,上為兄,下為弟;兄先于弟執行。
對于我們這個例子而言,執行完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】
over!?