溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Oracle如何解讀執(zhí)行計(jì)劃

發(fā)布時(shí)間:2021-11-11 11:13:55 來(lái)源:億速云 閱讀:228 作者:小新 欄目:關(guān)系型數(shù)據(jù)庫(kù)

這篇文章給大家分享的是有關(guān)Oracle如何解讀執(zhí)行計(jì)劃的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。


我先上一條語(yǔ)句,因?yàn)槲矣X(jué)得這條比較典型,所以我們就先用這條的執(zhí)行計(jì)劃來(lái)解讀下執(zhí)行計(jì)劃。
   

 Oracle如何解讀執(zhí)行計(jì)劃

然后是這條sql的我調(diào)整過(guò)的一個(gè)執(zhí)行計(jì)劃,我們本文主要是看執(zhí)行計(jì)劃的部分。

執(zhí)行計(jì)劃的開(kāi)頭

 首先不好意思,我把sql_id,plan_hash_value忘截圖了,基本上就是第一部分是執(zhí)行計(jì)劃的開(kāi)頭,有sql文本,sqlid,plan hash value,child number,這就不贅述了。

執(zhí)行計(jì)劃的正文

Oracle如何解讀執(zhí)行計(jì)劃

 先說(shuō)一下,這個(gè)正文的由來(lái),為了能看到starts,a-rows,a-time,buffers,0men,1mem... 所以,使用了:
alter sesssion set statistics_level=all;
select * from dbms_xplan.display_cursor(null,null,'advanced allstat');
所以說(shuō)我們這次主要說(shuō)的是以dbms_xplan包來(lái)看的執(zhí)行計(jì)劃內(nèi)容。

id,operation,name

      我們先籠統(tǒng)的介紹一下這個(gè)3個(gè)的意思跟由來(lái)。
     id:其實(shí)就是標(biāo)識(shí)每一個(gè)步步驟的一個(gè)序號(hào),就是跟個(gè)身份證似的,這個(gè)是從v$sql_plan的id列中得到的,并不代表他們執(zhí)行的順序,不過(guò)我稍后就會(huì)說(shuō)閱讀執(zhí)行計(jì)劃的順序及其原理。
     operation:是v$sql_plan中的operation列加上option列組合出來(lái)了,意思很淺顯,說(shuō)的就是這一步的操作。
     name:就是v$sql_plan中的object_name,也很明白,就是這一步操作的對(duì)象名稱。

     現(xiàn)在我們來(lái)解釋如果確定每一步的執(zhí)行順序。

      口訣隨便都能找到,就是看縮進(jìn),從左往右看,不對(duì)齊的,就是靠右的先執(zhí)行;到上下平行的或者說(shuō)對(duì)齊的(緊挨著的),那靠上的就比靠下的先執(zhí)行,然后再繼續(xù)右看,看到最右邊的時(shí)候就完事兒。其實(shí)這個(gè)看不太明白我說(shuō)的的,可以結(jié)合一下百度。
我直接說(shuō)原理,當(dāng)然也不是最底層實(shí)現(xiàn)的原理,那個(gè)現(xiàn)在還搞不來(lái)。
     從左往右看,靠右的先執(zhí)行是因?yàn)?,一個(gè)縮進(jìn)就代表了一對(duì)父子,兒子把自己的步驟得到的結(jié)果集整理好,上交給老子,就這么一回事兒。所以說(shuō)0-8的執(zhí)行順序是8 7 6 5 4 3 2 1 0.(我這里又要道歉,我有點(diǎn)兒蠢了,沒(méi)給大家選到那種有倆個(gè)
緊挨著的兒子的執(zhí)行計(jì)劃,所以這里先說(shuō)原理,大家這塊再結(jié)合下百度)
     然后當(dāng)你在找爹的路上往回走的時(shí)候,發(fā)現(xiàn)到了id=4這一步,往下看發(fā)現(xiàn)了個(gè)叔叔id=9,那這時(shí)候,4和9是并列的,也就是同輩兒的,那就先不著急再往3走,而是先去看看9有沒(méi)有兒子,確實(shí)有一個(gè),那按照靠右先執(zhí)行,應(yīng)該是10比9先執(zhí)行。
但是問(wèn)題是,4跟9誰(shuí)先執(zhí)行呢?因?yàn)椴⒘芯褪巧厦娴南葓?zhí)行,所以是4先執(zhí)行。然后又有人問(wèn)了,那9跟3又是怎么個(gè)順序呀,9跟4是兄弟,4是3兒子,也就是說(shuō)9也是3兒子,當(dāng)然是兒子先做收集結(jié)果集嘍。那現(xiàn)在得到的順序就成了 8-7-6-5-4-10-9-3-2-1-0。
     然而,當(dāng)找到id=3得時(shí)候,又發(fā)現(xiàn),這個(gè)爸爸也有個(gè)同輩兒的,id=11,但是這個(gè)11沒(méi)正好就是個(gè)光棍兒,沒(méi)兒子。那就排出3比11先執(zhí)行。后面2 1 0都沒(méi)兄弟了,所以最終的執(zhí)行順序是8-7-6-5-4-10-9-3-11-2-1-0。
    
     這個(gè)說(shuō)起來(lái)很枯燥,讀起來(lái)簡(jiǎn)單其實(shí),現(xiàn)在我就說(shuō)下重點(diǎn),這個(gè)到底是怎么個(gè)實(shí)現(xiàn)的。
     其實(shí)這就是個(gè)二叉樹(shù),因?yàn)槲业谝淮螌懖┛?,很多沒(méi)考慮到,沒(méi)有把v$sql_plan中的position跟parent_id,還有樹(shù)的深度截圖出來(lái),很不好意思,所以口述下這倆個(gè)的圖形表現(xiàn)。就是他們?cè)谏厦孢@張執(zhí)行計(jì)劃圖片表現(xiàn):同一個(gè)縮進(jìn)度的就是position值
一樣的,只查一個(gè)縮進(jìn)度的就是父子關(guān)系,也就是說(shuō)id=3和id=11的parent_id都是2。
     現(xiàn)在我們來(lái)畫一下這個(gè)二叉樹(shù),二叉樹(shù)就是只有倆個(gè)叉,所以你不可見(jiàn)到說(shuō)誰(shuí)不遵守計(jì)劃生育偏要整3個(gè)孩子的。
Oracle如何解讀執(zhí)行計(jì)劃
   

     看,每個(gè)塊塊里的數(shù)字就是id。畫圖可以讓我們正著看執(zhí)行計(jì)劃,按id畫出來(lái)圖,然后再去理出執(zhí)行計(jì)劃的執(zhí)行順序。
     首先,第一個(gè)孩子都是往左邊畫,第二個(gè)孩子才是挨著往右邊畫,找其中典型的部分來(lái)說(shuō)明下,3下面的孩子是4,但是發(fā)現(xiàn)僅比3少一個(gè)縮進(jìn)的,或者說(shuō)與4同縮進(jìn)的還有9。那先發(fā)現(xiàn)的3所以,3畫左邊,9畫右邊。而9下面的有10,所以10畫9下面的左邊。
那有人問(wèn)了,照這么說(shuō),10跟5也是平行的,都比4少一個(gè)縮進(jìn),為啥不把10畫4下面,因?yàn)榫o挨著的是直系,往上找沒(méi)有緊挨著的爸爸了才去找老王。所以就按照這個(gè)原則畫,就畫出了這個(gè)執(zhí)行計(jì)劃的本質(zhì)。
     然后,就是怎么遍歷這棵樹(shù),后序遍歷,別問(wèn)為什么。后序遍歷:先左后右再根。也就是說(shuō)一直找到最左邊的節(jié)點(diǎn)(找到第一個(gè)緊挨著的并行的親兄弟的時(shí)候的最靠右的步驟,也就是這對(duì)親兄弟靠上的哥哥,執(zhí)行計(jì)劃的入口),然后往右找(這就是找親弟弟,這就是為啥靠上的先執(zhí)行),
沒(méi)有就往上找(找爹,縮進(jìn)靠右的步驟先執(zhí)行的原因)。
     最后,我們來(lái)看上面這副圖,是不是8-7-6-5-4-10-9-3-11-2-1-0?!你要真不知道后序遍歷咋遍歷,你百度百科,賊簡(jiǎn)單。

starts

      這個(gè)就是真實(shí)的這一個(gè)步驟的總的執(zhí)行次數(shù),你看上面所有步驟都只執(zhí)行了一次。

A-rows

     這個(gè)就是這一個(gè)步驟真實(shí)返回的行數(shù),actual rows。也就是說(shuō),最上面id=0那一步的a-rows就是這條查詢最總返回來(lái)的行數(shù)。

A-time

      這一步真實(shí)執(zhí)行的時(shí)間。最上面id=0那一步的a-time就是這條查詢的真實(shí)執(zhí)行時(shí)間。

buffers

      邏輯讀,這里沒(méi)顯示出reads,但是還是說(shuō)一下,reads就是物理讀。

0mem,1mem

      這是說(shuō)的hash join,sort,group by使用的PGA的內(nèi)存大小,具體我還沒(méi)驗(yàn)證清楚,好像0mem是用的PGA內(nèi)存,1mem是用的硬盤空間。

執(zhí)行計(jì)劃的Qurey Block Name

Oracle如何解讀執(zhí)行計(jì)劃

        
      這里可能不太被大家注意,但是我覺(jué)得初學(xué),這里還是應(yīng)該看一看的。所謂查詢塊,說(shuō)白了就是select的個(gè)數(shù)。這部分內(nèi)容,- 前面的數(shù)字是步驟id。
      我在這里用/*+ qb_name() */把查詢塊名固定了,就是方便自己閱讀,其實(shí)要是不用這個(gè),oracle會(huì)自己給查詢塊取名,而且也挺好懂的,都是以SEL$開(kāi)頭的,后面跟個(gè)數(shù)字。舉個(gè)例子,大家看10 - 這一行,A@zong2,我們回執(zhí)行計(jì)劃找一找,id=10走了一個(gè)索引。
你可能上來(lái)就看執(zhí)行計(jì)劃的時(shí)候會(huì)說(shuō),誒我去,這個(gè)索引是誰(shuí)的呀。這不qurey block這部分就告訴你了嘛!這查詢塊zong2上的a表的。這個(gè)zong2我要是取名兒,oracle會(huì)給它取名SEL$2,為啥?!因?yàn)楹?jiǎn)單的說(shuō),這是第二個(gè)select。
     希望初學(xué)者看這里的時(shí)候自己對(duì)著一行一行的回原計(jì)劃和原語(yǔ)句中找找。
     對(duì)了,這里我們發(fā)現(xiàn)一個(gè)在語(yǔ)句中并沒(méi)有的別名,from$_subquery$_007。我們回步驟4找一下,發(fā)現(xiàn)是VIEW,再看看它是qiurank1塊兒的,那就很明白了,這個(gè)就是整個(gè)qiurank1這個(gè)子查詢整體的一個(gè)view,說(shuō)白了就是這么一整塊,它并不是一個(gè)真實(shí)存在再oracle中的視圖,
提醒大家一下,執(zhí)行計(jì)劃中別看見(jiàn)view就是視圖。子查詢不展開(kāi),也是被當(dāng)view來(lái)對(duì)待的。
     綜上,我們是不是發(fā)現(xiàn),你從這部分內(nèi)容中,你可以發(fā)現(xiàn)具體操作的對(duì)象是誰(shuí)的,是屬于那個(gè)select的?!
     好,但是這部分的用途到這里還不算完,我們接著往后看。

執(zhí)行計(jì)劃的OUTLINE部分

Oracle如何解讀執(zhí)行計(jì)劃

      是不是看到這個(gè)/*+    */有點(diǎn)兒眼熟,沒(méi)錯(cuò),這就這條語(yǔ)句執(zhí)行使用的hint,其實(shí)使用hint也就是來(lái)控制這部分。這部分其實(shí)是真的告訴你執(zhí)行計(jì)劃里面到底干了些什么,當(dāng)然,有一些我還不太確定,比如merge(qba>qbb),no_access,這些目前就只能大致猜,原因很簡(jiǎn)單,
因?yàn)槲乙彩莻€(gè)初學(xué)者。Oracle如何解讀執(zhí)行計(jì)劃
      那有人可能要問(wèn)了,執(zhí)行計(jì)劃正文加上后面要介紹的謂詞條件,不就已經(jīng)告訴我們這條sql到底是怎么運(yùn)作的嗎?還看這個(gè)干嘛。關(guān)鍵就是,一般我們?nèi)リP(guān)注執(zhí)行計(jì)劃,就是因?yàn)閳?zhí)行計(jì)劃有問(wèn)題了。所以,我們光知道執(zhí)行計(jì)劃是怎么個(gè)流程還不夠,我們是不是還要知道怎么修改它,讓
它按照我們理想的姿勢(shì)走正確的道路?!對(duì)于老司機(jī),人家一眼就知道該加啥hint,但是對(duì)于初學(xué)者,我們還是老老實(shí)實(shí)看看outline,看看到底該加什么hint,或者說(shuō)該修改什么hint。
      就這個(gè)圖片我舉個(gè)例子,看到倒數(shù)第三行,index_rs_asc那一行,這一行明確告訴你有一步是走了索引,這一步就是走了qiurank塊里的x表的...索引,而且這個(gè)索引是RS_ASC:range scan升序的,說(shuō)明走這個(gè)索引是正常從左往右走的而且還是個(gè)index range scan。
     這一行下面,說(shuō)了個(gè)啥?!是不是再說(shuō)qiurank塊里的x表索引掃描完了,然后用rowid回表是用batched這種多塊掃描的方式回的表,自己可以去執(zhí)行計(jì)劃里面找找,就是id=8,7做的事情。還有往上看一行,leading那一行,這個(gè)hash join的順序是不是跟執(zhí)行計(jì)劃里面體現(xiàn)的一毛一樣,
那我們把這里后面的做一個(gè)順序調(diào)整,然后加入到sql的hint當(dāng)中,就像這條sql的hint所做的那樣,是不是就能輕易的把hash join的順序進(jìn)行調(diào)整,你說(shuō)你調(diào)整A和B不用看這個(gè)outline,那你調(diào)整子查詢那一整塊兒在hash join中的順序,你準(zhǔn)備咋調(diào)呀?!當(dāng)然,肯定有別的辦法,但是這樣做是不是
就很方便,后面你調(diào)整好這塊,然后在固定profile偷梁換柱的時(shí)候也方便呀。
     所以我覺(jué)得這里該好好了解,我還沒(méi)研究透,大家看到這篇文章的話,可以交流研討共同進(jìn)步。

執(zhí)行計(jì)劃的predicate information

Oracle如何解讀執(zhí)行計(jì)劃

    
     這個(gè)正經(jīng)沒(méi)啥可說(shuō)的,就很直白。前面的數(shù)字還是id,access代表用了索引,意思就是進(jìn)入這個(gè)索引塊跑了一圈兒。filter才是真正的過(guò)濾條件,也就是說(shuō)這是回了表以后在表上的過(guò)濾條件。自己對(duì)這執(zhí)行計(jì)劃一步一步的看。
    這里雖然很直白,但是很重要,如果你不看outline跟qurey block也就算了,這里你要是再不看,那讀執(zhí)行計(jì)劃其實(shí)還挺費(fèi)勁的,因?yàn)槟阋阉猩婕暗谋淼牧泻退饕幕拘畔⒎旁谂赃?,?duì)著sql自己分析,就很累。而且有的時(shí)候,你覺(jué)得是這個(gè)索引走對(duì)了,比如說(shuō)這條sql最后的條件,
你要是有一邊日期筆誤寫粗了,比如多加了個(gè)空格,出來(lái)的執(zhí)行計(jì)劃還是一毛一樣,但是predicate information就不一樣了。所以說(shuō),如果能看到這部分,還是要好好看一下。

執(zhí)行計(jì)劃的column projection

Oracle如何解讀執(zhí)行計(jì)劃

      這里我還是好好說(shuō)一下,雖然內(nèi)容不多,前面的數(shù)字還是id,keys就是說(shuō)明這里有排序(這部分我后面學(xué)習(xí)明白了我再補(bǔ)充)。
     大拿不一定看這里,但是對(duì)于初學(xué)者,看一看是有收獲的。這部分就是每一個(gè)步驟操作的列以及該列的數(shù)據(jù)類型。道理很簡(jiǎn)單,但是我們能學(xué)到一些東西,我們能通過(guò)這部分和執(zhí)行計(jì)劃正文了解到,每一步到底是在操作哪些列,我們看到你真正的排序操作,是在8 7 6一系列過(guò)濾后才開(kāi)始在5進(jìn)行
分析函數(shù)的排序,在完成最后的形成一個(gè)整體view之前,8 7 6 5都是帶著rowid在操作的。
     反正看這里,就是能從另一個(gè)維度來(lái)看執(zhí)行計(jì)劃。還是希望初學(xué)者還是看一看,我覺(jué)得還是有收獲的。

執(zhí)行計(jì)劃的note

Oracle如何解讀執(zhí)行計(jì)劃    
     這不多說(shuō)了,直接上個(gè)我總結(jié)的的圖,自己了解下吧。
Oracle如何解讀執(zhí)行計(jì)劃

Oracle如何解讀執(zhí)行計(jì)劃

感謝各位的閱讀!關(guān)于“Oracle如何解讀執(zhí)行計(jì)劃”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI