参数导致SQL Server中的表扫描

时间:2016-03-22 05:31:35

标签: sql-server performance

我有两个表a,b,主键是它们的索引。

要求:

如果@filter为空,请选择a,b的所有记录,否则按任何特定分隔符拆分@filter,找到b.PKey在过滤器中的记录。

当前实施:

declare @filter nvarchar(max)= ''

SELECT * 
FROM a
JOIN b ON a.PKey = b.aPKey
       AND (@filter = '' OR b.PKey IN (SELECT item FROM splitFunction(@filter))

我发现最后一个语句and (@filter = '' or b.PKey in (select item from splitFunction(@filter))将始终在表b上进行表扫描,只有当我删除@filter=''时,它才会更改为索引搜索。

有没有办法可以实现我的要求并且不会损害性能?

2 个答案:

答案 0 :(得分:1)

特别针对这种情况,你也可以试试这个:

DECLARE @filter nvarchar(max)= ''

IF @filter = ''
BEGIN
    SELECT * 
    FROM a
    JOIN b ON a.PKey = b.aPKey
END
ELSE 
BEGIN
    SELECT * 
    FROM a
    JOIN b ON a.PKey = b.aPKey
    WHERE b.PKey IN (SELECT item FROM splitFunction(@filter))
END

答案 1 :(得分:1)

对于常量,优化器可以根据给定值的统计数据计算出最佳计划。

当您使用变量时,您正在强制参数化,并且该计划将被设计为可以重复使用各种值。所以Optimizer使用扫描而不是搜索。要解决此问题,请在查询中停止使用局部变量,并将其用作存储过程中的参数

create procedure p1
@filter = ''
as
begin
SELECT * 
FROM a
JOIN b ON a.PKey = b.aPKey
       AND (@filter = '' OR b.PKey IN (SELECT item FROM splitFunction(@filter))
option (recompile)
end

这将为您提供正确的计划,就像我已将本地变量转换为参数的存储过程一样。