在WHERE子句中使用可空列

3
假设在SQL Server中有以下表定义:
CREATE TABLE MyTable (
  Id   UNIQUEIDENTIFIER NULL,
  Info VARCHAR(MAX)
)

还有一个查询:

DECLARE @id UNIQUEIDENTIFIER
DECLARE @info VARCHAR(MAX)
IF @id IS NOT NULL
BEGIN
  SELECT @info = Info
    FROM MyTable
    WHERE Id = @id
END

在这种情况下,Visual Studio静态代码分析器会产生以下错误:

警告:SR0007: Microsoft.Performance:Nullable 列可能导致谓词的最终结果被评估为NULL。

我不明白问题出在哪里。这个错误与性能有关;MSDN说我应该使用ISNULL() -- 但是与NULL进行相等比较总是false,对吧?我是否遗漏了什么,还是这个警告只是错了?

忽略此警告。该建议会影响性能。(https://dev59.com/EGs05IYBdhLWcg3wD90B) - Martin Smith
6个回答

4
我认为它指的是 WHERE 子句。它表示你的参数和列都可以为 NULL,在这种情况下,你的 WHERE 子句不再计算为 true/false。通过将可空列导入始终定义了一个值的列(通过 ISNULL),你的逻辑更加完善。

这是 Microsoft 对该错误的文档。

另外,据说 NULL 会使查询变慢一些。


啊哈!问题出在它们同时为NULL时,它才会抱怨——除非我用IF或更详细的WHERE子句来排除它,否则分析器就不会发现它。我不确定你所说的NULL会使查询变慢是什么意思。你是指可空列比不可空列慢吗?还是你在谈论ISNULL? - RickNZ
我认为可空列在获取/处理时比非可空列慢。但是我没有任何依据来支持这一点,所以请带着一颗可空的盐粒看待。=D - Mark Canlas

1

我认为这是一个虚假警告 - 你能否按情况或完全禁止该特定警告?

当你这样做时会发生什么?:

CREATE TABLE MyTable (
  Id   UNIQUEIDENTIFIER NOT NULL,
  Info VARCHAR(MAX)
)

将其更改为 NOT NULL 可消除该警告。我可能最终会抑制这个消息;但我想要确保我完全理解它为什么会发生,并在实际上是一个 bug 的情况下进行报告。 - RickNZ

1

我认为分析器可能没有考虑到你的IF语句。

在我看来,你的代码是正确的。


该消息抱怨的是可空列,而不是可空参数。另外,如果我将WHERE子句更改为:Id IS NOT NULL AND Id = @id@id IS NOT NULL AND Id = @id,该消息仍然存在。 - RickNZ

1

空值比较取决于设置。

当 SET ANSI_NULLS 为 ON 时,所有与 null 值的比较都会评估为 UNKNOWN。

当 SET ANSI_NULLS 为 ON 时,使用 WHERE column_name = NULL 的 SELECT 语句即使在 column_name 中有 null 值也返回零行。 使用 WHERE column_name <> NULL 的 SELECT 语句即使在 column_name 中没有 null 值也返回零行。

当 SET ANSI_NULLS 为 OFF 时,等于 (=) 和不等于 (<>) 比较运算符不遵循 ISO 标准。

这是从这里开始的。


-2
IF @id IS NOT NULL

应该被替换为

IF ISNull(@id, -1) <> -1

@Raj 这不就是和“如果 @id 不为空”一样吗?改变它的意义何在? - dan
那段代码实际上甚至无法编译,因为@id是GUID而不是INT。 - RickNZ
哎呀,我以为id是整数,抱歉。 - Raj

-3

@ Raj: "IF ISNull(@id, -1) <> -1"

我不会这样做,因为它实际上会替换表中的条目。


1
但不幸的是,我是新手,没有足够的积分(或声望)来发表评论 :( http://stackoverflow.com/faq - ram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接