存儲過程包含一組復雜的SQL語句,使生成存儲過程的執行計划的代價有些高。因此通常重用存儲過程的執行計划來代替生成新計划是有利的。但是有時候現有的計划可能不適用或者在重用期間可能不能提供最佳的處理策略。SQL Server重編譯存儲過程中的語句來生成一個新的執行計划以解決這個問題。
1、產生存儲過程重新編譯的要素 為提高SQL性能,不僅僅是只注意SQL語句寫法問題,也不僅是意味者提高硬件要求,我們也必須要關注存儲過程編譯的時機,以及影響存儲過程重新編譯的起因,也是改進性能的一項不可避免的因素。
影響存儲過程重新編譯因素:
a、存儲過程語句中引用常規表、臨時表或視圖架構變化(索引修改、創建……)
b、表索引或列上統計變化超過一定的閾值
c、存儲過程編譯時一個對象不存在,但是在執行期間創建
d、執行計划老化並釋放
e、表列上綁定值變化
f、 環境變化(Set)
g、參數的不確定性
2、表列上綁定值的變化
表結構如下:創建一張表並設置DateTimes默認值為當前時間 ,創建存儲過程信息如下
修改Test表中DateTimes綁定值信息,並執行,使用SQL Profiler工具查看存儲過程執行的信息(進行了重新編譯)
3、存儲過程語句中引用常規表、臨時表或視圖架構變化(索引修改、創建……) 當存儲過程中的臨時表……架構等發生變化也會導致存儲過程重新編譯。當我們修改了表架構時,原有的執行計划引擎將會被SQL放棄,當執行這個存儲過程時,SQL Server會自動檢測架構是否修改並重新編譯。
4、表索引或列上統計變化超過一定的閾值 Sqlserver 查詢是基於開銷查詢的,在首次生成執行計划時是基於多階段的分析優化才確定出較好的執行計划。而這些開銷的基數估計,是根據統計信息來確定的。統計信息其實就是對表的各個字段的總體數據進行分段分布數據庫默認都會自動維護。如何查看表的統計信息(展開表->選擇統計信息->右鍵屬性)
當統計數超過閾值是就會引起存儲過程重新編譯,(BUT)但是重新編譯可以生成一個與之前完成想同的執行計划這樣,重新編譯的開銷就是額外的開銷應當避免;如何避免不必要編譯這里提供兩種方法(未重新編譯):
1、保持原有的執行計划方案(keepfixedPlan)
2、關閉表自動統計信息(sp_autostats)
5、執行計划老化並釋放 SQL Server通過維護緩沖中執行計划的壽命來管理存儲過程緩沖的大小,如果一個存儲過程長時間未被重新執行,執行計划的壽命字段將下降為0,內存短缺時將把該計划從緩沖中刪除。當這種情況發生並且存儲過程被重新執行時,將生成一個新計划並將其緩沖到過程緩沖中,如果系統中有足夠的內存,未使用的計划在內存壓力增加之前不會被刪除。
查詢緩存執行計划方式:
Sys.dm_exec_cached_plans: 包含緩存的執行計划,每個執行計划對應一行。
Sys.dm_exec_plan_attributes: 這是一個系統函數,每一個執行計划都對應着一些屬性,在這個系統函數中包含着這些屬性。
Sys.dm_exec_sql_text: 這是一個系統函數,返回文字格式的執行計划。
Sys.dm_exec_query_plan: 這是一個系統函數,返回xml格式的執行計划。
刪除緩存方式:
清除全局緩存使用下面的語句:
DBCC DROPCLEANBUFFERS;
從全局緩存中清除執行計划,使用下面的語句:
DBCC FREEPROCCACHE;
清除某一個數據庫中的執行計划,使用下面的語句:
DBCC FLUSHPROCINDB(<db_id>);
清除一個特定的執行計划使用下面的語句:
DBCC FREESYSTEMCACHE(<cachestore>);
6、環境變化(Set) 所謂環境變化指的是SQL SERVER ManageMent Studio開發環境設置的變化
7、參數的不確定性 參數不確定性就很簡單了,在不少的存儲過程中都會編寫部分的業務邏輯信息,進行SQL拼接操作,但是不正當的拼接就會降低存儲過程的性能,導致執行存儲過程執行時執行計划中多出一步重新編譯操作從而降低了存儲過程的性能(案例見:高效安全式SQL拼接)
8、重新編譯執行時機
學習了影響存儲過程重新編譯因素后,有不少開發人員會問我們什么時候該讓存儲過程進行編譯什么時候又不該讓其編譯換句話來說,重新編譯應在什么時候執行??
a、當使用表(或對應的統計)中數據的分布變化或者表中添加了新的索引時。這時為查詢計划生成了一個策略提高了查詢性能時需重新編譯不要使用緩存計划;
b、當刪除一個對查詢性能沒有任何影響的索引時,這時對此查詢沒有任何影響時就不需要重新譯否則降低了緩沖效率添加了CPU額外的開銷
9、操作存儲過程編譯的方式 a、調用sp_recompile系統存儲過程(exec sp_recompile 'Test')對指定的表每次使用時進行編譯
b、使用WITH RECOMPILE子句(強制數據庫引擎每次重新生成執行計划,針對特定的存儲過程、或某一個比較特殊的存儲執行才會使用;使用With Recompile 生成的計划不會被緩存,也不會影響到原緩存的計划),
c、使用OPTIMIZE FOR查詢提示(RECOMPILE方式提供了完全不使用計划緩存的節奏。但有些時候特性謂語的執行計划被使用的次數很多,僅僅那些謂語條件產生大量返回結果集的參數編譯,我們可以考慮Optimize For參數)
使用了該參數會使得緩存的執行計划按照OPTIMIZE FOR后面的謂語條件來生成並緩存執行計划,這也可能造成不在該參數中的查詢效率低下,但是該參數是我們選擇的,因此通常我們知道哪些謂語條件會被使用的多一些。