今天碰到一个问题,有个存储过程执行须要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;