查询优化; Table.Column = @Param OR @Param IS NULL

时间:2012-05-30 12:12:51

标签: sql sql-server sql-server-2008 tsql

在使用类似条件的WHERE子句中Table.Column = @Param OR @Param IS NULL它不使用列上的INDEX。

是真的,如果是,那么如何编写这种也使用INDEX的查询

查询示例

SELECT Col1, Col2 ...
FROM Table
WHERE (Col1 = @col OR @col IS NULL)
AND   (Col2 = @col2 OR @col2 IS NULL)
AND   (Col3 = @col3 OR @col3 IS NULL)

任何帮助。

4 个答案:

答案 0 :(得分:5)

不幸的是,执行计划的生成并不像您期望的那样。

对于该单个查询,将创建单个计划。在创建该计划时,将选择并修复要使用的索引。无论您提供什么参数,始终使用相同的计划,相同的索引等都无关紧要。

otpimiser 尝试找到适合所有事件的最佳方案,但根据此类查询的性质,没有一个。计划产生的特征,你根本没有使用索引。


解决方案是使用动态SQL。这感觉不整洁,但如果您使用sp_executesql的参数化查询,它实际上可以非常结构化,并且非常高效。

以下是关于此主题的非常有用的文章的链接:dynamic search

这是非常深入的,但 是解决此问题的一种非常强大的方法。

答案 1 :(得分:0)

SELECT Col1, Col2 ...
FROM Table
WHERE EXISTS(
    SELECT Col1, Col2, Col3
    INTERSECT
    SELECT @col, @col2, @col3)

直观地说,这看起来应该非常糟糕,但SQL Server的查询优化器知道如何给予INTERSECT特殊处理,并在内部将其转换为(伪SQL)

SELECT Col1, Col2 ...
FROM Table
WHERE (Col1, Col2, Col3) IS (@col, @col2, @col3)
您可以在查询计划中看到

。如果这些列上有索引,它们可以并且确实可以使用。

我最初是从Paul White的Undocumented Query Plans: Equality Comparisons博客文章中选择的,这可能是一个有趣的进一步阅读。

答案 2 :(得分:-1)

为什么不试试这个:

SELECT Col1, Col2 ...
FROM Table
WHERE Col1 = IsNull(@col,Col1)
AND Col2 = IsNull(@col2,Col2)
AND Col3 = IsNull(@col3,Col3)

关于您的问题: 您的查询分析器说它不使用column1,2,3上的索引?你为所有3列做了一个索引?然后它应该使用它而不管其他OR IS NULL

答案 3 :(得分:-1)

尝试在所有where子句列上建立索引,并尝试使用更具结构化的查询,如下所示:

SELECT Col1, Col2 ... 
FROM Table 
WHERE Col1 = **COALESCE**(@col,Col1)
AND Col2 = **COALESCE**(@col2,Col2)
AND Col3 = **COALESCE**(@col3,Col3)

COALESCE()函数返回第一个非null参数,因此如果STATUS为NULL,它将返回''。