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

问题描述 投票:0回答:3

我有一个存储过程,如果使用硬编码值,如''='',在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`  

当我从我的应用程序调用它或者使用SQL Server中的execute语句直接执行它时,大约需要7到8分钟

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 ='')”会减慢查询速度,但如果我将''=''直接写入查询并执行,它运行正常。

sql-server
3个回答
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.批处理期间的禁用自动更新统计信息


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


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
© www.soinside.com 2019 - 2024. All rights reserved.