SQL Server裏書籤查找的性能傷害

在個人博客上,之前我常常談到SQL Serverl裏的書籤查找,還有它們帶來的不少問題。在今天的文章裏,我想從性能角度進一步談下書籤查找,還有它們如何拉低你整個SQL Server性能。html

書籤查找——反覆循環

若是你的非彙集索引不是個覆蓋非彙集索引,SQL Server的查詢優化器會引入書籤查找。對於從非彙集索引你返回的每一行,SQL Server須要在彙集索引裏或堆表裏進行額外的查找操做。sql

例如當你的的彙集索引包含3層,爲了返回必要的信息,對於每一行,你須要3頁額外的讀取。所以,查詢優化器再執行計劃裏選擇書籤查找操做,僅在有意義的時候發生——基於你查詢的選擇度。下圖展現了有書籤查找操做的執行計劃。緩存

一般人們不會太關注書籤查找,由於它們只執行幾回。若是你的查詢選擇度過低,查詢優化器會用匯集索引掃描或表掃描運算符直接掃描整個表。但只在SQL Server重用緩存的執行計劃,這個計劃是有屢次不一樣運行值,包含書籤查找的(基於最初提供的輸入值),所以這個狀況很容易發生,書籤查找反覆執行。
工具

爲了演示這個性能問題,接下來的查詢我指定查詢優化器使用特定的非彙集索引。查詢自己返回80000行,由於對於每一個查詢執行,SQL Server須要進行書籤查找80000次——反覆執行。 性能

CREATE PROCEDURE RetrieveData
AS
    SELECT * FROM Table1 WITH (INDEX(idxTable1_Column2))
    WHERE Column3 = 2
GO

下圖展現了查詢執行後的實際執行計劃。測試

執行計劃看起來很是恐怖(查詢優化器甚至啓用了並行計劃!),由於書籤查找運算符這裏執行了80000次,查詢自己產生了超過165000個邏輯讀!(邏輯讀個數能夠從STATISTIC IO裏獲取)。優化

接下來向你展現下,當你有不少並行用戶執行這個糟糕查詢時,SQL Server會發生什麼。我會使用ostress.exe(RML工具的一部分)來模擬100個並行用戶的查詢。spa

ostress.exe -Q」EXEC BookmarkLookupsPerformance.dbo.RetrieveData」 -n100 -q

在個人測試系統上花費了近15秒來完成100個並行查詢。在此期間,CPU佔用很高,由於SQL Server須要嵌套循環運算符來進行書籤查找操做。嵌套循環操做固然很佔CPU資源。設計

如今讓咱們修改索引設計,爲這個查詢建立覆蓋非彙集索引。有了非彙集索引,查詢優化器不須要再執行計劃裏進行書籤查找。一個非彙集索引查找就能夠返回一樣的結果:code

CREATE NONCLUSTERED INDEX idxTable1_Column2 ON Table1(Column3)
INCLUDE (Column2)
WITH (DROP_EXISTING = ON)
GO

此次當咱們再次用ostress.exe執行同個查詢,咱們看到每一個查詢在5秒內完成。和咱們剛纔看到的15秒有很大的區別。這就是覆蓋非彙集索引的威力:在咱們查詢裏氣門請求的數據均可以在非彙集索引裏直接找到,所以書籤查找就能夠避免。

小結

在這個文章裏我向你展現了很差的書籤查找會傷及性能。所以,對於重要的查詢快速完成查詢很是重要——而使用並行的書籤查找的執行計劃並非好的選擇。這裏覆蓋非彙集索引能夠幫到你。下次設計索引時能夠考慮下這個方法。

感謝關注!

原文連接:

https://www.sqlpassion.at/archive/2017/03/13/the-performance-penalty-of-bookmark-lookups-in-sql-server/

相關文章
相關標籤/搜索