我有一个存储过程,如果使用的是硬编码值,则会在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 ='')"减慢查询速度,但如果我写了' =''直接进入查询和执行,它运行正常。
答案 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