延續前文:[SQL Server] Parameter Sniffing: OPTION OPTIMIZE FOR VALUE
已知道 "OPTIMIZE FOR VALUE" 是:
- 指示 Query Optimizer 使用 事先自訂 的 特定值 來建立 Reuse 的 Execution Plan,節省 recompile 所耗用的系統資源。
- 減輕因 "先建續用" 的 Reuse Execution Plan 機制,所產生的效能不佳問題。
UNKNOWN 一詞,在 Oxford Dictionaries 解釋:
- NOUN: An unknown person or thing.
- ADJECTIVE: Not known or familiar.
那 "OPTIMIZE FOR UNKNOWN" 是什麼?
OPTIMIZE FOR UNKNOWN
OPTIMIZE FOR UNKNOWN 是
- 指示 Query Optimizer 使用 Statistical Data (而非 Initial Value),來取代 Query Optimization 階段的 Local Variable 之值。 這包含:使用 Forced Parameterization (強制參數化) 所建立的參數。
- Query Optimizer 不使用 Parameter Sniffing,不使用 Histogram(長條圖),僅使用 Density Vector(密度向量) 來執行評估 Cardinality Estimation(CE, 基數預估)。
- Query Optimizer 使用 Cardinality Estimation,來產生 最佳化的 Execution Plan。
- 但 OPTIMIZE FOR UNKNOWN 卻可能讓 Query Optimizer 產生效能不佳的 Execution Plan。
- 建立 Reuse 的 Execution Plan,節省 recompile 所耗用的系統資源。
"UNKNOWN" 字面上的意義容易理解,但 "OPTIMIZE FOR UNKNOWN" 實際運作的方式,是需要進一步討論的。
但使用 OPTIMIZE FOR UNKNOWN 建立 Reuse Execution Plan 是個好方法嗎?
- 有提高執行效能?
- 如何評估 Index 呢?
Compare
以 OPTIMIZE FOR UNKNOWN 為例:
若 @StateProvinceID= 32
- Not match Execution Plan, Bad
- 理想是 Logical Reads: 6,但卻因故誤用,而耗用到 218,差距 36.33 倍。
- 原本是 CPU Time(sec): 0.000448000,但卻因故誤用,而耗用到 0.001645000,差距 3.67 倍。
若 @StateProvinceID= 9
- 算是 Match Execution Plan
- 但該有的 Missing Index 建議 卻不見了!
將後續文章進一步討論 OPTIMIZE FOR UNKNOWN。
OPTIMIZE FOR VALUE/UNKNOWN
總括來說,使用 "OPTIMIZE FOR VALUE/UNKNOWN" 是
- 指示 Query Optimizer 在執行 Compile 與 Query Optimization 期間,使用 "OPTIMIZE FOR VALUE/UNKNOWN" 抵銷 Query Optimizer 預設的 Parameter Detection 行為。
- Query Optimizer 不 使用預設的 Parameter Detection 方式來執行 Query Optimization,改用 "OPTIMIZE FOR VALUE/UNKNOWN" 所指示的方式來執行 Query Optimization。
- 只有在 Query Optimization 階段才使用這些方法的值,來建立 Execution Plan,而不是在 Query Execution 階段。
OPTION OPTIMIZE FOR UNKNOWN
01. 建立 Stored Procedure: up_Parameter_OPTION_OPTIMIZE_FOR_UNKNOWN
- Use OPTION (OPTIMIZE FOR UNKNOWN);
- 指示 Query Optimizer 使用 Statistical Data (而非 Initial Value),來取代 Query Optimization 階段的 Local Variable 之值。 這包含:使用 Forced Parameterization (強制參數化) 所建立的參數。
- Query Optimizer 不使用 Parameter Sniffing,不使用 Histogram(長條圖),僅使用 Density Vector(密度向量) 來執行評估 Cardinality Estimation(CE, 基數預估)。
- Query Optimizer 使用 Cardinality Estimation,來產生 最佳化的 Execution Plan。
- 但 OPTIMIZE FOR UNKNOWN 卻可能讓 Query Optimizer 產生效能不佳的 Execution Plan。
- 建立 Reuse 的 Execution Plan,節省 recompile 所耗用的系統資源。
-- figure 01_Create_Proc_OPTION (OPTIMIZE FOR UNKNOWN)
02. 執行 Stored Procedure,輸入 Parameter: @StateProvinceID= 32
- Input Parameter: StateProvinceID= 32
- Use OPTION (OPTIMIZE FOR UNKNOWN);
沒有使用到 Good Execution Plan
-- figure 02_StateProvinceID_32_OPTION (OPTIMIZE FOR UNKNOWN)
03. 觀察 效能 STATISTICS 統計資訊: CPU, Disk IO
- 使用 XQuery 查詢 Execution Plan 的 Estimate Number of Rows。
-- figure 03_Get last performance statistics
- 實際回傳的資料列筆數是: 1。
- 但評估 Estimate Number of Rows 卻是: 265.054 ?
-- figure 04_Get last performance statistics
04. 由 SSMS 的 GUI 介面,觀察 Execution Plan 的 Estimate Number of Rows 也是: 265.054 ?
-- figure 05_Execution_Plan_EstimatedNumberofRows
-- figure 0502_Actual_Estimate_Rows
- Number of Rows Read: 19614
- Actual Number of Rows: 1
- Estimated Number of Rows: 265.054
- Estimated Number of Rows to be Read: 19614
-- figure 0503_Actual_Number_Estimated_Rows
- Actual Number of Rows: 1
- Number of Rows Read: 19614
- Estimated Number of Rows: 265.054
05. 由 SSMS 的 GUI 介面,觀察 Execution Plan: [Parameter List] and [Estimate Number of Rows]
- [Parameter List], [Parameter Runtime Value]: (32)
- [Estimate Number of Rows]: 265.054
-- figure 06_Execution_Plan_EstimatedNumberofRows_[OptimizeStatsUsage]_Statistics
Summary
Use OPTION (OPTIMIZE FOR UNKNOWN);
- Only use statistical data for during query optimization.
- Only use statistical data instead of the initial value.
- Specifies that the query optimizer use statistical data instead of the initial value to determine the value for a local variable during query optimization.
- Middle value, mediocre for Execution Plan
@StateProvinceID= 32
- Not match Execution Plan, Bad
- retun 1 row
- Index Scan - [IX_Address_AddressLine1_AddressLine2_City_StateProvinceID_PostalCode]
- LastElapsedTime(sec): 0.006785000
- LastCPUTime(sec)]: 0.001645000
- LastRows: 1
- EstimatedNumberofRows: 265.054
- Last_logical_reads: 218
- [OptimizeStatsUsage], [Statistics]: [IX_Address_StateProvinceID]
Changing Parameter Values @StateProvinceID = 9
01. 執行 Stored Procedure,輸入 Parameter: @StateProvinceID= 9
- Input Parameter: StateProvinceID= 9
- Use OPTION (OPTIMIZE FOR UNKNOWN);
改採 OPTION (OPTIMIZE FOR UNKNOWN) 方式來建立 Execution Plan 後,當 StateProvinceID=9,竟然 沒有 原本該有的 Missing Index 建議。
-- figure 11_StateProvinceID_9_OPTION (OPTIMIZE FOR UNKNOWN)
02. 觀察 效能 STATISTICS 統計資訊: CPU, Disk IO
- 實際回傳的資料列筆數是: 4,564。
- 但評估 Estimate Number of Rows 卻是: 265.054 ?
-- figure 12_Get last performance statistics
03. 由 SSMS 的 GUI 介面,觀察 Execution Plan 的 Estimate Number of Rows 也是: 265.054 ?
-- figure 13_Execution_Plan_EstimatedNumberofRows
-- figure 1302_Actual_Estimate_Rows
- Number of Rows Read: 19614
- Actual Number of Rows: 4564
- Estimated Number of Rows: 265.054
- Estimated Number of Rows to be Read: 19614
-- figure 1303_Actual_Number_Estimated_Rows
- Actual Number of Rows: 4564
- Number of Rows Read: 19614
- Estimated Number of Rows: 265.054
04. 由 SSMS 的 GUI 介面,觀察 Execution Plan: [Parameter List] and [Estimate Number of Rows]
- [Parameter List], [Parameter Runtime Value]: (9)
- [Estimate Number of Rows]: 265.054
-- figure 14_Execution_Plan_EstimatedNumberofRows_[OptimizeStatsUsage]_Statistics
Summary
Use OPTION (OPTIMIZE FOR UNKNOWN);
- Only use statistical data for during query optimization.
- Only use statistical data instead of the initial value.
- Specifies that the query optimizer use statistical data instead of the initial value to determine the value for a local variable during query optimization.
@StateProvinceID= 9
- Match Execution Plan, But unexpected issue: without missing index
- retun 4564 row
- Index Scan - [IX_Address_AddressLine1_AddressLine2_City_StateProvinceID_PostalCode]
- LastElapsedTime(sec): 0.118544000
- LastCPUTime(sec)]: 0.006451000
- LastRows: 4564
- EstimatedNumberofRows: 265.054
- Last_logical_reads: 218
- [OptimizeStatsUsage], [Statistics]: [IX_Address_StateProvinceID]
Sample Code
20180106_Parameter_Sniffing_OPTION_OPTIMIZE_FOR_UNKNOWN
https://drive.google.com/drive/folders/0B9PQZW3M2F40OTk3YjI2NTEtNjUxZS00MjNjLWFkYWItMzg4ZDhhMGIwMTZl?usp=sharing
參考資料
[SQL Server] Parameter Sniffing: OPTION OPTIMIZE FOR VALUE
http://sharedderrick.blogspot.tw/2018/01/sql-server-parameter-sniffing-option.html
沒有留言:
張貼留言