参数导致 SQL Server 中的表扫描
Posted
技术标签:
【中文标题】参数导致 SQL Server 中的表扫描【英文标题】:Parameter cause a table scan in SQL Server 【发布时间】:2016-03-22 05:31:35 【问题描述】:我有两个表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=''
时,它才会变为索引查找。
有什么方法可以实现我的要求并且不损害性能?
【问题讨论】:
请查看***.com/questions/31500/… @AbdulRasheed,谢谢,它有帮助,但似乎不是同一个问题。我的问题是连接条件@filter=''
导致表扫描。如果我删除它,将使用索引。
相关:Dynamic Search Conditions
首先我建议您的AND
部分不是连接条件,而是WHERE
条件。从功能上讲,将其置于 ON 或 WHERE 之间没有任何区别,但由于表达式未评估两个表之间的匹配,因此对我来说这是一个 where 条件。如果它是外连接会有所不同,但由于它是内连接,所以不会
您的实际问题可能是缓存的查询计划不正确或参数嗅探。如果您按照此处使用OPTIMIZE FOR UNKNOWN
,性能是否会提高:blogs.msdn.microsoft.com/sqlprogrammability/2008/11/26/…
【参考方案1】:
对于常量,优化器可以根据给定值的统计数据制定最佳计划。
当您使用变量时,您是在强制参数化,并且该计划将被设计为可重复用于各种值。所以优化器使用扫描而不是搜索。为了克服这个问题,请停止在查询中使用局部变量并将其用作存储过程中的参数
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
这将为您提供正确的计划,就像在存储过程中我已将您的局部变量转换为参数一样。
【讨论】:
是的,它有效!但是我仍然对此表示怀疑,如果这是由优化器引起的,为什么该语句不起作用?OPTION(OPTIMIZE FOR (@filter=''))
选项优化不起作用,因为@filter 是一个局部变量,并且在制定执行计划时优化器不知道它的值并进行粗略估计。这就是您的选项优化不起作用的原因。如果您在存储过程中使用相同的内容,它将起作用
我实际上是在存储过程中这样做的,它没有工作:(。一旦更改为option(recompile)
,它就会再次工作。
Now Optimize for 意味着优化器将创建带有选项 filter ='' 的计划,这意味着它必须返回所有值。即使 filter '' 仍然优化器会为 filter = '' 制定计划。所以你总是会得到扫描。当行数是静态的并且不会改变时,优化是很有帮助的。在您的情况下,作为输出的行数取决于过滤器的值。当 filter = '' 时扫描并在 filter '' 时搜索。有关更多信息,请参阅链接 - msdn.microsoft.com/en-us/library/ms181714%28SQL.100%29.aspx【参考方案2】:
专门针对这种情况,你也可以试试这个:
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
【讨论】:
是的,这行得通。但这里我的问题是一个可以解释清楚的例子。如果我们有多个表和多个过滤器。这种方式似乎行不通。 是的,如果您有多个表,那么这不会产生最佳解决方案。这就是我专门针对这个案例提到的原因。以上是关于参数导致 SQL Server 中的表扫描的主要内容,如果未能解决你的问题,请参考以下文章