查詢優化器核心剖析第四篇:從一個執行個體看執行計劃
系列文章索引:
<a href="http://www.agilesharp.com/u/admin/Blog.aspx/t-195" target="_blank"> 查詢優化器核心剖析第五篇:進一步的了解執行計劃</a>
這幾天也收到了一些朋友的來信說:為什麼你花這麼多的時間将這些東西,直接告訴我性能優化的方法就行了。這個問題,其實早就說過了:學習查詢優化器不是我們的目的,而是通過它,我們掌握SQL Server是如何處理我們的SQL的,掌握執行計劃,掌握為什麼産生I/O問題,為什麼CPU使用老高,為什麼你的索引加了不起作用…
如果,我告訴你,你去加個索引,換SAN存儲,這樣意義不大!資料庫優化就是這樣的:沒有所謂的“絕對手段,一下子把性能搞上去,一切都是看情況而定”,都是通過不斷的分析,抽絲剝解。不帶頭腦的優化,能好到那裡去?
在前幾篇文章中,我們已經談了一些查詢優化器的相關的基礎介紹,也大緻的了解了它到底是幹什麼的。查詢優化器的結果就是産生執行計劃,執行計劃就是一個樹,這個樹由很多的實體操作組成,而這些實體操作就定義了如何去儲存設備中去擷取資料。
我們可以以很多的不同的方式,例如圖形化,文本,XML的形式來檢視一個給定查詢的實際的執行計劃和估計的執行計劃。這些不同格式的執行計劃的差別主要在于包含的資訊的詳細程度不同。
當需要檢視一個查詢的實際的執行計劃的時候,這個查詢比較要執行。然而,如果檢視估計的執行計劃,此時整個查詢是不需要實際執行的。如果查詢是個需要消耗很長時間,很多資源的查詢,我們在分析問題的時候,會先檢視這個查詢估計的執行計劃,并且這樣做也不會對使用資料庫的其他使用者産生影響。
檢視實際執行計劃和估計的執行計劃方式有很多,最簡單的方式就是在SQL Server管理界面點選如下按鈕:
檢視估計的執行計劃:
<a href="http://www.agilesharp.com/Services/BlogAttachment.ashx?AttachmentID=88" target="_blank"></a>
檢視實際的執行計劃 :
<a href="http://www.agilesharp.com/Services/BlogAttachment.ashx?AttachmentID=89" target="_blank"></a>
下面,我們就來通過一個簡單的示例講述執行計劃,這裡采用示例資料庫:AdventureWorks。
我們在SQL Server中輸入以下查詢:
<a href="http://www.agilesharp.com/Services/BlogAttachment.ashx?AttachmentID=90" target="_blank"></a>
然後,點選“Include Actual Execution Plan”按鈕,然後執行SQL語句,看到如下顯示:
<a href="http://www.agilesharp.com/Services/BlogAttachment.ashx?AttachmentID=91" target="_blank"></a>
在圖中,我們可以看到一些實體操作符号以圖示顯示,例如Index Scan,Hash Aggregate。第一個圖示稱為結果操作符,它傳回了查詢的結果。
每一個實體的操作符,其實就是存儲引擎中實作的一些基本的操作或者方法。例如,一個邏輯的join(就是我們在SQL寫的inner join之類的),可以再執行計劃中以不同的實體join操作實作(Nested Loops Join, Merge Join, Hash Join)。當然,這裡沒有所謂的“那種實體操作好,哪種不好”,得看具體情況。
每個實體操作執行的時候,就會去擷取一些資料,然後将資料傳遞給它下一個實體操作,知道全部的操作完成,傳回結果。在檢視執行計劃的時候,需要“從右向左,從下到上”進行。
在執行計劃中,每個實體操作都有一些“箭頭”相連,這些箭頭就表明了執行的先後順序,并且箭頭的粗細也放映了傳遞資料的多少,越粗就表明資料越多。
我們可以通過把滑鼠放在這些箭頭上面,檢視更多的資訊。如下:
<a href="http://www.agilesharp.com/Services/BlogAttachment.ashx?AttachmentID=92" target="_blank"></a>
通過檢視提示資訊,我們可以知道:Index Scan這個操作讀取了19614條資料,這些資料之後被傳遞給了Hash Aggregate操作。Hash Aggregate執行之後,就将這些資料通過City字段做了一個distinct的處理,将575條資料給了下一個操作:
<a href="http://www.agilesharp.com/Services/BlogAttachment.ashx?AttachmentID=94" target="_blank"></a>
對于執行計劃中出現的一些實體操作,一般基本會通過三個方法來實作它們的功能(這裡要把操作和方法的概念搞清楚,可能在很多的程式設計語言中,一個操作就是一個方法,或者說操作就是方法,這裡的操作和方法和那些不同,一個操作是有幾個方法來實作和完成的,為了便于了解,大家這裡就把每一個操作了解為一個類吧):
Open()方法:這個方法初始化一個實體操作
GetRow()方法:這個方法每次都從它的上一個操作中擷取一行資料
Close()方法:執行完畢,做一些相關的清理等工作
因為GetRow()方法每次隻能從上一個操作中擷取一個資料,那麼如果上一個操作傳遞了很多的資料,那麼這個實體操作就要多次調用上一個操作的GetRow()方。在上面的例子中,Hash Aggregate操作隻調用一次Index Scan的Open()方法,然後調用19615次Index Scan的GetRow()方法,最後調用一次Index Scan的Close()方法。
其實我們還可以通過這個圖形化的執行計劃得到更多的資訊!為了使得大家更好地消化今天的知識,餘下的内容,下次接着講述。
本文轉自yanyangtian51CTO部落格,原文連結: http://blog.51cto.com/yanyangtian/814688,如需轉載請自行聯系原作者