在where where条件下使用sp参数时,过程性能会降低

时间:2015-08-21 12:53:12

标签: sql-server

我有一个存储过程,如果使用的是硬编码值,则会在4秒内执行,例如' =''在如下所示的条件下:

alter procedure proc1
( @filter varchar(400)=null )
as
begin 
select a,b,c from tbl1 where ''=''
end

但当我将其作为存储过程参数传递时,如下所示:

alter procedure proc1
( @filter varchar(400)=null )
as
begin
select a,b,c from tbl1 where @filter=''
end`  
当我从我的应用程序中调用它时,大约需要7到8分钟 或者使用SQL Server中的execute语句直接执行它

exec proc1 ''

上面给出的sp只是一个例子。该过程实际上很大,包括许多select语句和用户定义的函数,但问题出现在上面给出的类似语句中。

条件:

  where 
et.X is not null and et.Y is not null and e.EquipmentName is not null AND e.Available='Available'

--and (Select dbo.GetFilterStatusOfEquipment(getdate(),'70','50','ON'))='*'
AND (
(dbo.GetFilterStatusOfEquipment(et.SignalDateTime,et.SpeedOfTheVehicle,(SELECT COUNT(J.JobId) FROM tbl_Notification J 
               inner JOIN tbl_NotificationAssign JN ON  JN.NotificationNo =J.NotificationNo
               inner JOIN dbo.tbl_CustomStatus JS ON JS.CustomStatusID=J.CustomStatusID 
               INNER JOIN dbo.tbl_SystemStatus ss ON ss.SystemStatusID=JS.SystemStatusID
               WHERE JN.DriverID=et.DriverID AND ss.SystemStatusID !=9),et.IgnitionStatus) 
              in (Select val from Split(@filter,',')) or (@filter='')))

and (et.CompanyID=@CompanyID or @CompanyID='') AND e.Flag_Delete='0'

GetFilterStatusOfEquipment和Split是UDF。

"或(@filter ='')"减慢查询速度,但如果我写了' =''直接进入查询和执行,它运行正常。

3 个答案:

答案 0 :(得分:0)

1.使用未直接显示在参数上的虚拟变量也可确保执行计划的稳定性,而无需添加重新编译提示,例如:

alter procedure proc1
( @filter varchar(400) = NULL)
as
begin 
  declare @filterDummy varchar(400)
  set @filterDummy  = @filter

  select a,b,c from tbl1 where @filterDummy = ''
end

2.要防止此情况和其他类似情况,您可以使用以下查询选项:

OPTIMIZE FOR
RECOMPILE

3.批处理期间的禁用自动更新统计信息

答案 1 :(得分:0)

也许您的查询很复杂,SQL Server需要很长时间才能生成计划。

在这种情况下,如果您的统计信息是自动更新的,我建议您使用动态查询和sp_executesql以及查询选项KEEPFIXEDPLAN。

Declare @Query nvarchar(max),@QueryParameters nvarchar(max)

Set @Query='select a,b,c from tbl1 where @filter='''' OPTION(KEEPFIXED PLAN)'
Set @QueryParameter='@filter varchar(400)'

sp_executesql @Query,@QueryParameters,@filter=@filter

选项KEEPFIXED PLAN仅在您启用自动更新统计信息时使用。

以下是使用KEEPFIXED PLAN选项重新编译商店流程的文章:https://support.microsoft.com/en-us/kb/276220

答案 2 :(得分:0)

当您使用以下表达式时:
    in (Select val from Split(@filter,',')) or (@filter=''

et.CompanyID=@CompanyID or @CompanyID=''
如果[CompanyID]列具有索引或[CompanyID]是主键,则执行计划包含索引'scan operator'而不是'index seek'运算符。

在这种情况下,您应该生成查询。

例如:

alter procedure proc1
( @filter varchar(400)=null )
as
begin
  declare @query nvarchar(1000)
  set @query='select * from tbl'
  if (@filter<>'')
    set @query=@query+' where id in (Select val from split(@filter,'',''))'

  EXECUTE sp_executesql @query ,
  N'@filter nvarchar(30)',
  @filter =@filter
end

或使用IF语句

alter procedure proc1
( @filter varchar(400)=null )
as
begin
  if (@filter<>'')
    select * from tbl 
    where id in (Select val from split(@filter,','))
  else 
    select * from tbl 
end