【问题标题】:Does wrapping nullable columns in ISNULL cause table scans?在 ISNULL 中包装可空列会导致表扫描吗?
【发布时间】:2011-09-19 13:30:48
【问题描述】:

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

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    它声称理由是

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

    虽然表达式本身的计算结果为unknown,但一旦您了解任何=、<>、>、< 等与NULL 的比较评估为@987654331 @ 并且 WHERE 子句仅返回表达式计算结果为 true 的行。

    他们的意思可能是如果ANSI_NULLS 关闭,但他们在WHERE ISNULL([c2],0) > 2; 与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 
    

    【讨论】:

    • ORDER BY 子句中的语法是什么? (我用谷歌搜索过,但搜索起来有点困难......)
    • @AakashM - 这是迄今为止我发现的按常数排序的最少打字方式,以便获得升序的数字序列。 over (order by(SELECT 0)) 或 over (order by @@spid) 是备选方案。您不能使用文字常量值,因为 SQL Server 会给您一个错误。除以零可防止将其视为文字常量。您不能使用 1/0 作为 SQL Server 您尝试按整数列序号排序的东西并引发错误。
    • 哦,我明白了,$ 被解释为值为零的 money 文字!解析器的慷慨令人惊讶,我不得不说:)
    • AakashM: SELECT SQL_VARIANT_PROPERTY($,'BaseType')
    • @MartinSmith 对线程死灵表示歉意,但您能详细说明第三个查询的执行计划吗?为什么只添加OR x IS NULL 就添加了这么长的操作链? Constant Scan + Compute Scalar + Concatenation + Sort + Merge 的全部意义是什么?这是一个“便宜”的执行计划吗?为什么 SQL Server 不够聪明,无法推断出第一个查询的 intent 与第三个查询相同并使用相同的执行计划? (我针对 SQL Server 2019 运行它,计划与您的屏幕截图中的计划相同,我假设是 2008 R2 或 2012。
    猜你喜欢
    • 2017-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多