SQL Server OPTION (OPTIMIZE FOR UNKNOWN) 測試總結


 

關於SQL Server的查詢提示OPTION (OPTIMIZE FOR UNKNOWN) ,它是解決參數嗅探的方法之一。 而且對應的SQL語句會緩存,不用每次都重編譯。關鍵在於它的執行計划的准確度問題, 最近在優化的時候,和同事對於這個查詢提示(Query Hint)有一點分歧,遂動手實驗驗證、總結了一些東西。

 

關於提示OPTION (OPTIMIZE FOR UNKNOWN),它會利用統計數據和標准算法生成一個折中、穩定的執行計划,但是它是無法利用直方圖(histogram)信息來生成執行計划。官方文檔的介紹如下:

 

OPTIMIZE FOR 編譯和優化查詢時提示查詢優化器對本地變量使用特定值。僅在查詢優化期間使用該值,在查詢執行期間不使用該值。

 

UNKNOWN

指定查詢優化器在查詢優化期間使用統計數據而不是初始值來確定局部變量的值。OPTIMIZE FOR 可以抵消優化器的默認參數檢測行為,也可在創建計划指南時使用

 

OPTIMIZE FOR UNKNOWN

指示查詢優化器在查詢已經過編譯和優化時為所有局部變量使用統計數據而不是初始值,包括使用強制參數化創建的參數。有關強制參數化的詳細信息,請參閱強制參數化

如果在同一查詢提示中使用 OPTIMIZE FOR @variable\_name = literal_constant OPTIMIZE FOR UNKNOWN,則查詢優化器將對特定的值使用指定的 literal_constant,而對其余變量使用 UNKNOWN。這些值僅用於查詢優化期間,而不會用於查詢執行期間

 

OPTIMIZE FOR UNKNOWN是否會用直方圖數據呢? 不會,OPTIMIZE FOR UNKNOWN只會用簡單的統計數據。我們以how-optimize-for-unknown-works這篇博客中的例子來演示一下, 下面測試環境為SQL Server 2014,數據庫為AdventureWorks2014

 

CREATE PROCEDURE test (@pid int)
AS
SELECT * FROM [Sales].[SalesOrderDetail]
WHERE ProductID = @pid OPTION (OPTIMIZE FOR UNKNOWN);

 

 

為了消除統計信息不准確會干擾測試結果,我們手工更新一下統計信息。

 

UPDATE STATISTICS [Sales].[SalesOrderDetail] WITH FULLSCAN;

 

 

我們在SSMS里面點擊包含實際執行計划選項,然后測試執行該存儲過程,如下截圖所示: 執行計划居然走聚集索引掃描

 

EXEC test @pid=709

 

clip_image001

 

 

Filter里面過濾的記錄為456.079,而實際上ProductID=709的記錄有188條,那么優化器是怎么估計判斷記錄數為456.709的呢?

 

clip_image002

 

clip_image003

 

 

其實優化器是這樣來估計的:它使用ProductID列的密度(Density)* Rows來計算的

 

SELECT 0.003759399 *121317 ~= 456.079008483 ~= 456.079

 

ProductID列的密度(Density)的計算是這樣來的:

 

ProductID的值有266個,可以用下面SQL獲取ProductID的值個數

 

 

SELECT COUNT(DISTINCT ProductID) FROM  Sales.SalesOrderDetail

 

SELECT 1.0/266  ~=  0.003759

 

 

然后你可以使用任意不同的參數測試,例如707712......, 你會發現使用查詢提示OPTION (OPTIMIZE FOR UNKNOWN)后,優化器會總是使用相同的執行計划。也就是說這個查詢提示生成的執行計划是一個折中的執行計划 ,對於數據分布傾斜的比較厲害(數據分布極度不均衡)的情況下,是極度不建議使用查詢提示OPTION (OPTIMIZE FOR UNKNOWN)的。

 

本人曾經一度對使用OPTIONRECOMPILE)還是OPTION (OPTIMIZE FOR UNKNOWN)感到困惑和極度難以取舍,后面總結了一下:

 

1:執行不頻繁的存儲過程,使用OPTIONRECOMPILE)要優先與OPTION (OPTIMIZE FOR UNKNOWN)

 

2:執行頻繁的存儲過程,使用OPTION (OPTIMIZE FOR UNKNOWN)要優先於OPTIONRECOMPILE

 

3:數據分布傾斜的厲害的情況下,優先使用OPTIONRECOMPILE

 

    4: 使用OPTION (OPTIMIZE FOR UNKNOWN)會生成一個穩定、統一的執行計划,如果這個執行計划的效率基本能滿足用戶需求,那么優先使用OPTION (OPTIMIZE FOR UNKNOWN)

 

 

 

 

 

參考資料:

 

https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008/ms181714(v=sql.100)

http://www.benjaminnevarez.com/2010/06/how-optimize-for-unknown-works/

https://blogs.msdn.microsoft.com/sqlprogrammability/2008/11/26/optimize-for-unknown-a-little-known-sql-server-2008-feature/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM