在ISNULL中包装可空列是否会导致表扫描?

时间:2011-09-19 13:30:49

标签: sql-server sql-server-2008 tsql sql-server-data-tools datadude

Visual Studio 2010数据库项目的代码分析规则SR0007表明:

  

您应该通过在ISNULL函数中包装每个可以包含NULL值的列来明确指出如何处理比较表达式中的NULL值。

但是,在以下情况下违反了代码分析规则SR0006

  

作为比较的一部分,表达式包含列引用...如果代码比较包含列引用的表达式,则代码可能会导致表扫描。

这是否也适用于ISNULL,或者ISNULL是否永远不会导致表扫描?

1 个答案:

答案 0 :(得分:18)

是的,它导致表扫描。 (虽然如果列实际上不可为空,似乎会得到优化)

SR0007规则是极其糟糕的一揽子建议,因为它使谓词不可分割并且意味着列上的任何索引都将是无用的。即使列上没有索引,它仍可能使基数估计值不准确,影响计划的其他部分。

它在Microsoft.Performance类别中的分类非常有趣,因为它似乎是由不了解查询性能的人编写的。

它声称理由是

  

如果您的代码将两个NULL值或NULL值与任何其他值进行比较   值,您的代码将返回未知结果。

虽然表达式本身确实评估为unknown,但一旦您理解了任何=<>><,您的代码就会返回完全确定的结果与NULL的比较等式为UnknownWHERE子句仅返回表达式求值为true的行。

他们可能意味着ANSI_NULLS已关闭,但他们在WHERE ISNULL([c2],0) > 2; vs WHERE [c2] > 2;的文档中提供的示例无论如何都不会受此设置的影响。此设置

  仅当比较的一个操作数是

时,

才会影响比较   要么是NULL变量,要么是文字NULL。

执行计划显示扫描与搜索或以下

CREATE TABLE #foo
  (
     x INT NULL UNIQUE
  )

INSERT INTO #foo
SELECT ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM   sys.all_columns

SELECT *
FROM   #foo
WHERE  ISNULL(x, 10) = 10

SELECT *
FROM   #foo
WHERE  x = 10

SELECT *
FROM   #foo
WHERE  x = 10
        OR x IS NULL 

enter image description here