Sql 查询优化;Table.Column=@Param或@Param为空

Sql 查询优化;Table.Column=@Param或@Param为空,sql,sql-server,sql-server-2008,tsql,Sql,Sql Server,Sql Server 2008,Tsql,在WHERE子句中,当使用类似于此表的条件时。Column=@Param或@Param为NULL时,它不会对列使用索引 这是真的吗?如果是,那么如何编写这种同样使用索引的查询 查询示例 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) 任何帮助。为什么不试试

在WHERE子句中,当使用类似于此表的条件时。Column=@Param或@Param为NULL时,它不会对列使用索引

这是真的吗?如果是,那么如何编写这种同样使用索引的查询

查询示例

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)
任何帮助。

为什么不试试这个:

SELECT Col1, Col2 ...
FROM Table
WHERE Col1 = IsNull(@col,Col1)
AND Col2 = IsNull(@col2,Col2)
AND Col3 = IsNull(@col3,Col3)
关于你的问题:
您的查询分析器说它不使用第1、2、3列上的索引?您为所有3列创建了索引?然后它应该使用它,而不管另一个
或为NULL

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

对于单个查询,将创建单个计划。在创建该计划时,要使用的索引是选定的,并且是固定的。无论您提供什么参数,始终使用相同的计划、相同的索引等

otpimiser试图找到适合所有可能发生的情况的最佳计划,但根据这种类型查询的性质,没有一个。一个由你根本没有使用索引的计划产生的特征


解决方案是使用动态SQL。这感觉很不整洁,但如果您将参数化查询与sp_executesql一起使用,它实际上可能非常结构化,而且性能非常好

以下是一个链接,指向一篇关于该主题的非常有用的文章:


它非常深入,但它是解决此问题的一种非常稳健的方法。

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

SELECT Col1, Col2 ... 
FROM Table 
WHERE Col1 = **COALESCE**(@col,Col1)
AND Col2 = **COALESCE**(@col2,Col2)
AND Col3 = **COALESCE**(@col3,Col3)
函数的作用是:返回第一个非null参数,因此如果STATUS为null,它将返回“”

从直觉上看,这似乎应该表现得非常糟糕,但SQL Server的查询优化程序知道如何给予
INTERSECT
特殊处理,并在内部将其转换为(伪SQL)

正如您在查询计划中所看到的。如果您在这些列上有索引,它们可以而且确实会被使用


我最初是从Paul White的博文中读到这篇文章的,这可能是一篇有趣的进一步阅读。

很抱歉没有格式化我的问题。编辑器没有给我选项和预览。我不知道为什么。它并没有提高性能,但这个条件可以用更优雅的方式编写:col1=isnull(@col,col1)这里是关于动态搜索条件的一个非常完整的参考:通过查看SSMS中的执行计划,您可以很容易地看到查询是否使用索引。@heximal-如果数据中有空值,isnull方法将返回不同的结果。isnull方法将数据与equal运算符进行比较。Null不等于Null,因此该行将被过滤掉。使用原始帖子中的代码,将返回该行。如果isnull方法不能生成正确的输出,则不能认为它“更优雅”。就生成执行计划而言,这与OP已经经历的行为完全相同。简而言之,不幸的是,这没有帮助。我不怀疑你是对的,但我不明白为什么执行计划不使用他的索引。在我的答案中有一个链接,链接到一篇文章,解释了很多。我在回答中触及了表面,但给出一个完整的答案就等于写一篇文章。不幸的是,最好读一下这个链接。由于我在回答中提到的原因,以及我链接的文章中提到的原因,这不会有任何区别。(这在对问题的评论中被联系了起来。)还有一种方法。但我不认为这对你们的生产环境有什么可行性。在主表上为主键创建索引。然后在最后的查询中,只需搜索主键并将记录放入temp。桌子现在为临时表上的所有列创建一个索引。最后从temp表中编写select查询,这就是好的ORM工具在后台所做的。回答得很好。
SELECT Col1, Col2 ...
FROM Table
WHERE EXISTS(
    SELECT Col1, Col2, Col3
    INTERSECT
    SELECT @col, @col2, @col3)
SELECT Col1, Col2 ...
FROM Table
WHERE (Col1, Col2, Col3) IS (@col, @col2, @col3)