延續前文:[SQL Server] Parameter Sniffing: OPTION OPTIMIZE FOR UNKNOWN 2
使用 "Local Variables / OPTIMIZE FOR UNKNOWN"
- 如果無法識別出 常用 的 parameter 值,或是 Query Optimizer 使用此 parameter 值所 compile 的 Execution Plan 效率不佳(例如:由於 data skew 數據傾斜)。
- SQL 開發人員 設定 Query Optimizer 僅使用 Average Distribution (平均分配) 機制來執行 cardinality estimation。
- 至於輸入什麼 parameter,回傳多少筆數,讓 Query Optimizer 都不要列入考量,也不使用 Parameter Sniffing。
- 在此次範例中,甚至連該有的 Missing Index 建議也不見了!
- "Local Variables / OPTIMIZE FOR UNKNOWN" 這兩者是相同功能。
- 先前,若要停用 Parameter Sniffing ,要對每一個 Input Parameter,額外再多宣告對應出 Local Parameter 來承接。
- 在 SQL Server 2008 可以改用 OPTIMIZE FOR UNKNOWN,這是 SQL Statement 陳述式層級方式來 停用 Parameter Sniffing。
使用 "Local Variables / OPTIMIZE FOR UNKNOWN" 建立 Reuse Execution Plan 是個好方法嗎?
- 有提高 執行效能?
- 如何評估 Index 呢?
評估方式
"Local Variables / OPTIMIZE FOR UNKNOWN"
Conditions | Query Optimizer only use |
equality: = | Rows * All density |
inequality: > , < , etc., | Rows * 30% |
當條件式是:
- 使用 equality (等號),則 Query Optimizer 僅使用 density vector 來執行 Cardinality Estimation,也就是: Rows * All density。
- 使用 Inequality (不相等),則 Query Optimizer 連 density vector 也不用了,就直接設定資料列總數的 30% 來執行 Cardinality Estimation,也就是: Rows * 30% 。
試想:
- 這種方式建立出來的 Execution Plan 會有好的效能嗎?
- 這會是 效能最佳化 的 Execution Plan 嗎?
Compare Match and Not match Execution Plan
以 Local Variables / 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 建議 卻不見了!
Local Variable and Equality Operator
01. 建立 Stored Procedure: up_Parameter_Local_Variable
- Use Input Parameter
- Use Local Variable
- Use Equality Operator
- SQL 開發人員 為了要 停用 Parameter Sniffing,設定 Query Optimizer 僅使用 Average Distribution (平均分配) 機制來執行 Cardinality Estimation。
- 至於輸入什麼 parameter,回傳多少筆數,讓 Query Optimizer 都不要列入考量。
要達成 停用 Parameter Sniffing 方法是:
- 額外再宣告 Local Variable。
- 承接來自於 Input Parameter 的值
- 設定條件式僅使用 Local Variable。
-- figure 01_Local Variable
02. 設定 Input Parameter: @StateProvinceID= 32,執行此 Stored Procedure。
- Input Parameter: StateProvinceID= 32
- Use Local Parameter
- Actual Number of Rows 是: 1。
- Index Scan: [IX_Address_AddressLine1_AddressLine2_City_StateProvinceID_PostalCode]
- 但評估 Estimate Number of Rows 卻是: 265.054 ?
Local Variable 與 OPTIMIZE FOR UNKNOWN 兩者是一樣的功能,有著相同的 誤用問題!
-- figure 02_Local Variable_StateProvinceID_32
03. 由 SSMS 的 GUI 介面,觀察 Execution Plan
- StatementEstRows="265.054"
- OptimizeStatsUsage
在 OptimizeStatsUsage,可以看是 Statistics: [IX_Address_StateProvinceID]。
也就是說,Query Optimizer 是使用 Index: [IX_Address_StateProvinceID] 的 statistics (統計資料),執行 Query Optimization。
-- figure 03_OptimizeStatsUsage
04. Show Execution Plan XML,可以到相關的資訊。
- 在 OptimizeStatsUsage,可以看是 Statistics: [IX_Address_StateProvinceID]。
-- figure 04_XML_OptimizeStatsUsage
Changing Parameter Values @StateProvinceID = 9
01. 執行 Stored Procedure,輸入 Parameter: @StateProvinceID= 9
- Input Parameter: StateProvinceID= 9
- Use Local Parameter
改採 Use Local Parameter方式來建立 Execution Plan 後,當 StateProvinceID=9,竟然 沒有 原本該有的 Missing Index 建議。
由 SSMS 的 GUI 介面,觀察 Execution Plan 的 Estimate Number of Rows 也是: 265.054 ?
-- figure 11_Local Variable_StateProvinceID_9
後續的相關測試,請參考先前的文章:
[SQL Server] Parameter Sniffing: OPTION OPTIMIZE FOR UNKNOWN 2
"Local Variables / OPTIMIZE FOR UNKNOWN" 這兩者是相同功能,有著相同的 誤用問題!
Local Variable and Inequality Operator
Use Inequality Operators, 使用 不相等
01. 建立新的 Stored Procedure: up_Parameter_Local_Variable_Inequality,使用 Inequality Operators。
- Use Local Parameter
- Use < (Less Than) Operators
-- figure 21_inequality
02. 執行 Stored Procedure,輸入 Parameter: @StateProvinceID= 2
- Number of Rows Read: 19614
- Actual Number of Rows: 25
- Estimated Number of Rows: 5884.2
- Estimated Number of Rows to be Read: 19614
Use Local Parameter,使用 < (Less Than)
- return 25 rows
- 但為什麼 EstimatedNumberofRows 卻是 5884.2 ?
為什麼是使用 EstimatedNumberofRows: 5884.2 來評估建立 Execution Plan 呢?
-- figure 31_inequality_StateProvinceID_2_Execution_Plan
03. 再度更換 Parameter: @StateProvinceID= 181
- Number of Rows Read: 19614
- Actual Number of Rows: 19583
- Estimated Number of Rows: 5884.2
- Estimated Number of Rows to be Read: 19614
Use Local Parameter,使用 < (Less Than)
- return 19583 rows
- 但為什麼 EstimatedNumberofRows 卻是 5884.2 ?
怎麼又是使用 EstimatedNumberofRows: 5884.2 來評估建立 Execution Plan 呢?
-- figure 41_inequality_StateProvinceID_181_Execution_Plan
後續的相關測試,請參考先前的文章:
[SQL Server] Parameter Sniffing: OPTION OPTIMIZE FOR UNKNOWN 2
"Local Variables / OPTIMIZE FOR UNKNOWN" 這兩者是相同功能,有著相同的 誤用問題!
Sample Code
20180116_Parameter_Sniffing_Local_Variable
https://drive.google.com/drive/folders/0B9PQZW3M2F40OTk3YjI2NTEtNjUxZS00MjNjLWFkYWItMzg4ZDhhMGIwMTZl?usp=sharing
參考資料
[SQL Server] Parameter Sniffing: OPTION OPTIMIZE FOR UNKNOWN 2
http://sharedderrick.blogspot.tw/2018/01/sql-server-parameter-sniffing-option_14.html
沒有留言:
張貼留言