在where条件下,T-SQL为空

在where条件下,T-SQL为空,sql,sql-server,tsql,Sql,Sql Server,Tsql,我正在寻找意见,可能是对以下问题的具体答案。 此问题适用于SQL Server 2008 R2版+ 在存储过程中,我有一个日期类型的可选查询参数,我们将其称为@MyVar 存储过程执行以下查询: SELECT A, B, C FROM MyTable WHERE MyTable.Field1 = ISNULL(@MyVar,MyTable.Field1) 做这项工作的成本是多少ISNULL@MyVar,MyTable.Field1,如果@MyVar为空? 我想知道是否最好将以下情况分开: IF

我正在寻找意见,可能是对以下问题的具体答案。 此问题适用于SQL Server 2008 R2版+

在存储过程中,我有一个日期类型的可选查询参数,我们将其称为@MyVar

存储过程执行以下查询:

SELECT A, B, C
FROM MyTable
WHERE MyTable.Field1 = ISNULL(@MyVar,MyTable.Field1)
做这项工作的成本是多少ISNULL@MyVar,MyTable.Field1,如果@MyVar为空? 我想知道是否最好将以下情况分开:

IF (@MyVar IS NULL)
    SELECT A, B, C
    FROM MyTable
ELSE
    SELECT A, B, C
    FROM MyTable
    WHERE MyTable.Field1 = @MyVar

谢谢

更优雅的方法是:

SELECT A, B, C
FROM   MyTable
WHERE  MyTable.Field1 = @MyVar
   OR  @MyVar IS NULL
OPTION(RECOMPILE)
SELECT A, B, C
FROM MyTable
WHERE @MyVar IS NULL AND MyTable.Field1 IS NOT NULL
UNION ALL
SELECT A, B, C
FROM MyTable
WHERE @MyVar IS NOT NULL AND MyTable.Field1 = @MyVar
编辑

根据@JamesZ的建议,添加了optionrecompile,以便在字段1上使用索引(如果存在)

edit2感谢@Y.B.指出这一点

如果field1也可以为null,请使用以下内容:

SELECT A, B, C
    FROM   MyTable
    WHERE  MyTable.Field1 = @MyVar
       OR  (@MyVar IS NULL AND MyTable.Field1 IS NULL)
    OPTION(RECOMPILE)

这已经显示了“一网打尽”查询的问题。例如,您还可以将上一个查询中的AND替换为OR,这将给出另一个理论结果集,但也可能是正确的。

为了获得最佳性能,有两个过程,一个采用@MyVar,另一个不采用@MyVar。这样,您就可以为每个案例获得一个查询计划,而不是您看到的第一个案例

让客户端调用任何一个有意义的调用,这取决于您是否有要使用的值

如果您担心重复代码,请为您的查询添加一个视图

SELECT A, B, C
    FROM MyTable
从中选择有意义的条件。 这不是魔法。不幸的是,没有一刀切的办法。

请注意

SELECT A, B, C
FROM MyTable
WHERE MyTable.Field1 = ISNULL(@MyVar,MyTable.Field1)
不会返回字段1为空的记录,而

会的

从技术上讲,重写原始表达式的正确有效方法是:

SELECT A, B, C
FROM   MyTable
WHERE  MyTable.Field1 = @MyVar
   OR  @MyVar IS NULL
OPTION(RECOMPILE)
SELECT A, B, C
FROM MyTable
WHERE @MyVar IS NULL AND MyTable.Field1 IS NOT NULL
UNION ALL
SELECT A, B, C
FROM MyTable
WHERE @MyVar IS NOT NULL AND MyTable.Field1 = @MyVar

它确实阻止了索引的使用,因为您将field1与无法索引的每个字段计算值进行比较。您的意思是MyTable.field1在结尾处=@MyVar。@MarcB我不明白为什么它会阻止使用Indexe可能是因为解析器足够聪明,可以将OP的查询转换为下面的@honeybadger版本,但是isnull是一个函数调用,将对每一行进行求值。在所有其他条件相同的情况下,isnull的结果将不会预先存储/计算,这意味着查询将执行完整的表扫描并计算每一行。由于这是我们在搜索等事情中经常看到的模式,因此有些人将其称为“捕获所有查询”。从性能的角度来看,有一些重要的考虑因素需要考虑。看看Gail Shaw关于这个主题的这篇伟大的文章。这仍然不使用索引,但显然更易于阅读,尽管我会添加括号以防止将来出现错误。@JamesZ,如果添加更多条件,当然可以添加括号。我不确定您对索引的理解。在评论中有一个关于索引用法的讨论-如果Field1被索引,即使@MyVar不为null,它也不会被使用,除非使用了选项“重新编译”。@JamesZ,有趣的是,我没有意识到这一点。添加到应答中。@从技术上讲,当MyTable.Field1为空且@MyVar为空时,此查询输出将不同于OP的第一个查询