計劃緩存

今天我想進一步談下SQL Server裏的計劃緩存和它的反作用。咱們都知道,每一個提交到SQL Server的邏輯查詢,會編譯爲物理執行計劃。這個執行計劃而後會緩存爲所謂的計劃緩存,用於後期重用。如今咱們首先來談下即席SQL語句和它的負做用,還有它們帶來的性能問題。html

即席SQL語句(Adhoc SQL Statements)

每次當你提交一個即席SQL語句到SQL Server,對於每一個特定查詢,都會生成一個執行計劃。「特定查詢」是什麼意思?答案很簡單:SQL Server對每一個完整的SQL語句(包括你的參數值)生成一個哈希值,並使用這個哈希值做爲計劃緩存的查找值。若是使用這個哈希值找到一個執行計劃,計劃就會重用,不然在計劃緩存裏會編譯一個新的執行計劃。假設你提交下列3個查詢到SQL Server:sql

SELECT * FROM Sales.SalesOrderHeader
WHERE CustomerID = 11000
GO

SELECT * FROM Sales.SalesOrderHeader
WHERE CustomerID = 30052
GO

SELECT * FROM Sales.SalesOrderHeader
WHERE CustomerID = 11223
GO

對於這3個查詢,SQL Server編譯3個不一樣的執行計劃,由於你提供了硬編碼的參數值。所以3個查詢間會計算不一樣的的哈希值,不會找到已緩存的計劃。做爲反作用,在計劃緩存裏,如今你有近3個近乎同樣的查詢有3個不一樣的計劃。這個特定問題被稱爲計劃緩存污染緩存

你剛用不一樣的執行計劃污染了你的計劃緩存,這很難重用(由於硬編碼的參數值),並且你在浪費能夠被SQL Server裏其它組件使用的有用內存。緩存的目的應該提升重用數,但使用即席SQL語句就作不到。性能

計劃穩定性

假設你爲你的SQL語句使用參數值,或者你甚至使用存儲過程。在這個狀況下,SQL Server很是容易重用緩存的執行計劃。但即便重用緩存的執行計劃,你回引入性能問題。例如SQL Server爲一個查詢編譯了一個執行計劃,它回進行書籤查找,由於非彙集索引沒有覆蓋你的查詢:優化

 

咱們提過,書籤查找只有在從表裏獲取一些數據纔有意義。若是你越過了臨界點,使用全表掃描或彙集索引掃描更高效。但若是SQL Server衝了緩存的執行計劃,這個選項就不會考慮太多——SQL Server會盲目重用你的計劃——這時你的性能就會不好!能夠看下面的例子:編碼

這裏SQL盲目重用了有書籤查找的緩存計劃。你會看到估計和實際行數有很大差異!SQL Server在假設從查詢裏只返回一條記錄來編譯和緩存計劃。但實際上從SQL Server咱們拿回1499條記錄。你看到的執行計劃,是假設只有一條記錄返回的狀況下優化——考慮下這個狀況。spa

這裏潛在的根源是你的計劃不穩定。基於估計行數,你獲得有書籤查找的緩存計劃,若是你越過臨界點,會是表/彙集索引掃描。這是咱們常常碰到的常見SQL Server性能問題。code

你如何解決這個問題?簡單:經過覆蓋非彙集索引來避免書籤查找。使用這個方法你會得到計劃穩定性,無論你的輸入參數,你會獲得一樣的性能。htm

小結

今天你學到了SQL Server裏,計劃緩存的雙刃劍:在一方面,計劃緩存很是強大,由於你能夠重用計劃緩存避免編譯資源佔用。在另外一方面,他很是危險,使用定型的執行計劃,你的計劃再也不穩定,這就意味着你不能再保證性能。blog

感謝關注!

原文連接

https://www.sqlpassion.at/archive/2017/03/20/plan-caching/

相關文章
相關標籤/搜索