今天碰到一個問題,有個存儲過程執行須要1分鐘,可是把存儲過程複製出來,將參數賦值,而後執行,只要6秒。後來終於發現是Parameter sniffing問題。sql
原存儲過程:ide
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在存儲過程執行以前都會制定一個執行計劃。spa
從網上找到的解決方式:code
一、用變量替換掉參數(已驗證,舉例以下)blog
二、將受影響的sql語句隱藏起來,好比:input
a) 將受影響的sql語句放到某個子存儲過程當中,好比咱們在@thedate設置成爲今天后再調用一個字存儲過程將@thedate做爲參數傳入就能夠了。event
b) 使用sp_executesql來執行受影響的sql。執行計劃不會被執行,除非sp_executesql語句執行完。class
c) 使用動態sql(」EXEC(@sql)」來執行受影響的sql。變量
使用第一種方法修改後:cli
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;