翻譯(十一) ——Reading Query Plans: Stairway to SQL Server Indexes Level 9

Reading Query Plans: Stairway to SQL Server Indexes Level 9sql

 

By David Durant, 2011/10/05數據庫

原文連接:http://www.sqlservercentral.com/articles/Stairway+Series/72441/數據庫設計

 

 

The Series編輯器

 

本文是階梯系列的一部分:SQL Server索引的階梯。函數

 

索引是數據庫設計的基礎,並告訴開發人員使用數據庫大量關於設計者的意圖。不幸的是,當性能問題出現時,索引經常會做爲過後考慮添加。這裏最後是一系列簡單的文章,應該能讓數據庫專業人員快速地與它們同步。工具

 

在整個步驟中,咱們常常聲明某個查詢以某種方式執行;咱們引用生成的查詢計劃來支持咱們的語句。管理庫顯示估計和實際查詢計劃,能夠幫助您肯定索引的好處或不足。所以,這個級別的目的是讓您對查詢計劃有足夠的瞭解:sqlserver

 

當你閱讀這個階梯時,驗證咱們的斷言。性能

 

肯定索引是否有利於查詢。優化

 

有許多文章閱讀查詢計劃,包括MSDN Library中的幾個。咱們不打算擴展或替換它們。事實上,咱們將在這個級別爲他們中的許多人提供連接/引用。開始的好地方是顯示圖形執行計劃。(http://msdn.microsoft.com/en-us/library/ms178071.aspx). 其餘有用的資源包括Grant Fritchey的書,SQL執行計劃(可用於電子書免費),和Fabiano Amorim的一系列簡單的對話篇關於各運營商發現您的查詢計劃的輸出(http://www.simple-talk.com/author/fabiano-amorim/).spa

 

 

 

Graphical Query Plans

 

  查詢計劃是SQLServer執行查詢時所遵循的一組指令。SQLServer將以文本、圖形或XML格式顯示對您的查詢計劃。例如,考慮下面的簡單查詢:

 

    SELECT LastName, FirstName, MiddleName, Title 

 

FROM Person.Contact

 

WHERE Suffix = 'Jr.'

 

ORDER BY Title

 

這個查詢的計劃能夠如圖1所示。

 

 

1 -圖形格式的實際查詢計劃

或者,能夠將其視爲文本:

|--Sort(ORDER BY:([AdventureWorks].[Person].[Contact].[Title] ASC))


|--Clustered Index
Scan(OBJECT:([AdventureWorks].[Person].[Contact].[PK_Contact_ContactID]),
WHERE:([AdventureWorks].[Person].[Contact].[Suffix]=N'Jr.'))

或者做爲一個XML文檔,從這樣開始:

 

 

查詢計劃的顯示能夠以下所示要求:

要請求圖形化查詢計劃,請使用管理室的SQL編輯器工具欄,該工具欄同時具備「顯示估算執行計劃」和「包含實際執行計劃」按鈕。「顯示估計的執行計劃」選項顯示查詢計劃圖當即爲選定的TSQL代碼,而不執行查詢。「包含實際執行計劃」按鈕是一個開關,一旦您選擇了這個選項,您執行的每一個查詢批將在一個新選項卡中顯示查詢計劃圖,以及結果和消息。這個選項能夠在圖1中看到。

要求文本查詢計劃,使用設置showplan_text聲明。打開文本版本將關閉圖形版本,不會執行任何查詢。

要查看XML版本,在圖形版本中右擊,並從上下文菜單中選擇「顯示執行計劃XML」。

對於這個級別的其他部分,咱們專一於圖形視圖,由於它一般提供對計劃的最快的理解。對於查詢計劃,一個圖片一般比一千個詞更好。

 

Reading Graphical Query Plans

圖形查詢計劃一般從右向左讀取;右最圖標表示數據收集流中的第一步。這一般是訪問堆或索引。您不會看到這裏使用的字表;相反,您將看到集羣索引掃描或堆掃描。這是第一個查看哪些索引(若是有的話)正在使用的地方。

圖形化查詢計劃中的每一個圖標表示一個操做。在可能的圖標的更多信息,參見圖形執行計劃在http://msdn.microsoft.com/en-us/library/ms175913.aspx圖標

 

 

鏈接操做的箭頭表示行,從一個操做流出並進入下一個操做。

將鼠標放在圖標或箭頭上會致使顯示更多信息。

不要把操做看做步驟,由於這意味着在下一個操做開始以前必須完成一個操做。這不必定是真的。例如,當對WHERE子句進行求值時,也就是說,當執行篩選器操做時,一次一行求值,而不是一次求值。在後續行到達篩選器操做以前,一行能夠移動到下一操做。另外一方面,排序操做必須在第一行移動到下一操做以前所有完成。

 

Using Some Additional Information

   圖形化查詢計劃顯示了兩個可能有用的信息,這些信息不是計劃自己的一部分;建議的索引和每一個操做的相對成本。

在上面的例子中,所提出的指標,顯示綠色和空間要求截斷,建議聯繫表的後綴列的非彙集索引;包括標題、FirstNameMiddleName列,和姓。

這個計劃的每一個操做的相對成本告訴咱們,排序操做佔總成本的5%,而表掃描是工做的95%。所以,若是咱們想改進這個查詢的性能,咱們應該處理表掃描,而不是排序,這就是爲何建議索引的緣由。若是咱們建立推薦索引,像這樣:

CREATE NONCLUSTERED INDEX IX_Suffix ON Person.Contact
(
Suffix
)
INCLUDE ( Title, FirstName, MiddleName, LastName )

而後從新運行查詢,咱們的讀取量從569降低到3;新的查詢計劃以下所示。

新的非彙集索引,其索引鍵後綴,有「後綴=Jr.」條目彙集在一塊兒;所以,在IO須要檢索數據還原。所以,排序操做與前一個計劃中的排序操做相同,如今表明了查詢總成本的75%以上,而不是原來的5%。所以,原始計劃須要75/5倍於當前計劃收集相同信息的工做量的15倍。

因爲咱們的WHERE子句只包含一個相等運算符,所以咱們能夠經過將標題列移動到索引鍵來改進索引:

IF  EXISTS (SELECT * FROM sys.indexes
WHERE OBJECT_ID = OBJECT_ID(N'Person.Contact')

AND name = N'IX_Suffix')
DROP INDEX IX_Suffix ON Person.Contact
CREATE NONCLUSTERED INDEX IX_Suffix ON Person.Contact
(
Suffix, Title
)
INCLUDE ( FirstName, MiddleName, LastName )

如今,所需的條目仍然在索引中彙集在一塊兒,而且在每一個集羣中都在請求的序列中;如新的查詢計劃所示,如圖2所示。

 

 

2查詢計劃重建非聚簇索引後

如今計劃代表再也不須要排序操做。在這一點上,咱們能夠放棄高收益的覆蓋指數。這將使聯繫人表恢復到咱們開始時的狀態;當咱們進入下一個話題時,這是咱們但願它處於的狀態。

 

Viewing Parallel Streams

    若是能夠並行處理兩行行,它們將在圖形顯示中彼此上下顯示。箭頭的相對寬度指示經過每一個流處理的行數。

例如,下面的鏈接將前面的查詢擴展爲包含銷售信息:

SELECT C.LastName, C.FirstName, C.MiddleName, C.Title
, H.SalesOrderID, H.OrderDate
FROM Person.Contact C
JOIN Sales.SalesOrderHeader H ON H.ContactID = C.ContactID
WHERE Suffix = 'Jr.'
ORDER BY Title

查詢計劃如圖3所示。

3 -鏈接的查詢計劃

快速看一下這個計劃會告訴咱們一些事情:

兩個表同時掃描。

大部分的工做都花在掃描桌子上。

多排出來或salesorderheader表超過了接觸表。

兩表不聚爲同一序列;所以每一個salesorderheader行行匹配的接觸將須要額外的努力。在這種狀況下,使用哈希匹配操做。(稍後再討論散列)。

排序所選行所需的努力能夠忽略不計。

即便是單獨的行行也能夠分解成單獨的行,以利用並行處理。例如,若是咱們將上面查詢中的WHERE子句改成後綴爲null的地方。

將返回更多的行,由於95%的聯繫人行有一個空後綴。新的查詢計劃反映了這一點,如圖4所示。

4 -一個並行查詢計劃

新計劃還向咱們代表,接觸行數的增長致使匹配和排序操做成爲該查詢的關鍵路徑。若是咱們須要提升它的性能,咱們必須首先攻擊這兩種操做。一樣,包含列的索引將有助於。

和大多數鏈接同樣,咱們的示例經過外鍵/主鍵關係鏈接兩個表。其中的一個表,聯繫,是先由ContactID,這也正好是其主要的關鍵。在其餘表中,saleorderheader ContactID是外鍵。自從ContactID是外鍵,用於數據訪問的saleorderheader ContactID請求,如我加入的例子,多是一種常見的業務需求。這些請求將從索引ContactID效益。

每當您對外鍵列進行索引時,老是問本身,若是列中包含了列,那麼應該添加哪些索引。在咱們的例子中,咱們只有一個查詢,而不是一個支持查詢的家庭。所以,咱們只包括將OrderDate列。支持一個家庭的ContactID導向對saleorderheader表查詢,咱們將包括在索引中,列的更多saleorderheader的須要,以支持那些額外的查詢。

咱們的建立索引語句是:

CREATE NONCLUSTERED INDEX IX_ContactID ON Sales.SalesOrderHeader
(
ContactID
)
INCLUDE ( OrderDate )

而新計劃的執行咱們的salesorderheader和聯繫信息加入如圖5

 

5 -計劃在每一個表上有一個支持索引的鏈接查詢

因爲輸入流如今是由謂詞鏈接柱、ContactID;測序加入部分的查詢能夠作到不裂流無散列;從而減小26 + 5 + 3 = 34%的工做負載下4%的工做負載是什麼。

 

Sorting, Presorting and Hashing

許多查詢操做要求在執行操做以前將數據分組。這些包括明確的,聯盟(這意味着不一樣),按組(及其各類聚合函數),並加入。一般,SQL Server將使用三種方法中的一種來實現這種分組,第一種方法須要您的幫助:

高興地發現數據已經被預設爲分組序列。

經過執行哈希操做將數據分組。

將數據排序到分組序列中。

 

Presorting

指標是你的預存數據;即在常常須要對SQL Server提供的數據序列。這就是爲何非彙集索引的建立,每一個包含包含性列,得益於咱們以前的例子。事實上,若是將鼠標放在最近查詢中的合併鏈接圖標上,則短語將使用兩個適當排序的輸入流匹配行,利用它們的排序順序。將出現。這將告訴您兩個表/索引的行是使用內存和處理器時間的絕對最小值來鏈接的。相應排序的輸入是一個精彩的短語看到當鼠標查詢計劃的圖標,它驗證了你選擇的指標。

 

Hashing

若是輸入的數據不是理想的序列,SQLServer可使用哈希操做對數據分組。哈希是一種可使用大量內存的技術,但一般比排序效率更高。當執行不一樣,聯盟,加入行動,散列在單個行能夠經過下一步操做無需等待全部的輸入行被哈希排序優點。可是,在計算分組彙集時,必須在將全部聚合值傳遞給下一個操做以前讀取全部輸入行。

散列信息所需的內存量與所需的組數直接相關。所以須要解析散列:

SELECT Gender, COUNT(*)
FROM NewYorkCityCensus
GROUP BY Gender
只須要不多的內存,由於只有兩個組:女性和男性,無論輸入行數。另外一方面:
SELECT LastName, FirstName, COUNT(*)
FROM NewYorkCityCensus
GROUP BY LastName, FirstName

將致使大量的組,每一個組都須要在內存中擁有本身的空間;可能消耗了太多的內存,哈希成爲解決查詢的不可取的技術。

更多的查詢計劃哈希,訪問http://msdn.microsoft.com/en-us/library/ms189582.aspx

 

Sorting

若是數據沒有預設(索引),若是SQL Server認爲散列不能高效完成,SQL Server將數據排序。這一般是最不可取的選擇。所以,若是在計劃早期出現排序圖標,請檢查是否能夠改進索引。若是Sorticon出如今計劃結束時,這可能意味着SQL ServerORDER BY子句的請求序列排序的最終輸出;這種序列與序列被用來解決查詢的鏈接、分組、和工會。一般,在這一點上你能夠作些什麼來避免這種排序。

 

Conclusion

查詢計劃顯示SQL Server打算使用或使用的方法來執行查詢。它經過詳細說明將要使用的操做、從操做到操做的行流以及所涉及的並行性。

您將此信息視爲文本、圖形或XML顯示。

圖解顯示每一個操做的相對工做負荷。

圖形化計劃可能會提供一個索引來提升查詢的性能。

理解查詢計劃有助於評估和優化索引設計。

相關文章
相關標籤/搜索