今天碰到一個問題,有個存儲過程執行需要1分鍾,但是把存儲過程復制出來,將參數賦值,然后執行,只要6秒。后來終於發現是Parameter sniffing問題。
原存儲過程:

IF ( OBJECT_ID('sp_yp_jxctj', 'P') IS NOT NULL ) DROP PROC sp_yp_jxctj; GO /*======================================================== 描述: 系統: 引用: 輸入: 輸出: 備注: 修改記錄: ==========================================================*/ CREATE PROC sp_yp_jxctj @startDate VARCHAR(50) , --開始時間 @endDate VARCHAR(50) , --結束時間 @inputCode VARCHAR(24) , --輸入碼 @deptCode VARCHAR(20) , --科室代碼 @drugType CHAR(2) , --葯品類型 @drugAttr VARCHAR(20) , --葯品屬性 @dosage VARCHAR(20) , --劑型 @drugState INT , --葯品狀態 @rate INT --零差率 AS BEGIN ---------------------------- --內容省略 ---------------------------- end;
在SQL Server中有一個叫做 “Parameter sniffing”的特性。SQL Server在存儲過程執行之前都會制定一個執行計划。
從網上找到的解決方式:
1、用變量替換掉參數(已驗證,舉例如下)
2、將受影響的sql語句隱藏起來,比如:
a) 將受影響的sql語句放到某個子存儲過程中,比如我們在@thedate設置成為今天后再調用一個字存儲過程將@thedate作為參數傳入就可以了。
b) 使用sp_executesql來執行受影響的sql。執行計划不會被執行,除非sp_executesql語句執行完。
c) 使用動態sql(”EXEC(@sql)”來執行受影響的sql。
使用第一種方法修改后:

IF ( OBJECT_ID('sp_yp_jxctj', 'P') IS NOT NULL ) DROP PROC sp_yp_jxctj; GO /*======================================================== 描述: 系統: 引用: 輸入: 輸出: 備注: 修改記錄: ==========================================================*/ CREATE PROC sp_yp_jxctj @startDate VARCHAR(50) , --開始時間 @endDate VARCHAR(50) , --結束時間 @inputCode VARCHAR(24) , --輸入碼 @deptCode VARCHAR(20) , --科室代碼 @drugType CHAR(2) , --葯品類型 @drugAttr VARCHAR(20) , --葯品屬性 @dosage VARCHAR(20) , --劑型 @drugState INT , --葯品狀態 @rate INT --零差率 AS BEGIN --用變量替換掉參數,以防出現“Parameter sniffing”問題 DECLARE @deptType INT , @startDate1 VARCHAR(50) = @startDate , --開始時間 @endDate1 VARCHAR(50) = @endDate , --結束時間 @inputCode1 VARCHAR(24) = @inputCode , --輸入碼 @deptCode1 VARCHAR(20) = @deptCode , --科室代碼 @drugType1 CHAR(2) = @drugType , --葯品類型 @drugAttr1 VARCHAR(20) = @drugAttr , --葯品屬性 @dosage1 VARCHAR(20) = @dosage , --劑型 @drugState1 INT = @drugState , --葯品狀態 @rate1 INT = @rate; --零差率 ---------------------------- --內容省略 ---------------------------- END;