我有两个表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=''
时,它才会更改为索引搜索。
有没有办法可以实现我的要求并且不会损害性能?
答案 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
这将为您提供正确的计划,就像我已将本地变量转换为参数的存储过程一样。