where子句顺序对SQL查询速度的影响

时间:2016-10-08 01:27:25

标签: sql sql-server sqlperformance

我遇到一个问题,在SQL-Server上,复杂查询的运行速度慢得令人无法接受(每个事务大约10秒)。我不确定版本,但至少2005年。 查询将相应变量匹配大约40个字段(列),并返回所有字段匹配的行,或者字段和变量都为空。 至少前几个字段是索引的。 就目前而言,查询中的第一个字段几乎与每条记录都匹配。会重新排序查询,以便首先放置不太可能匹配的字段,当发现不匹配时,允许在给定行上提前终止查询吗? 还有什么其他加速可以建议吗?

重新命名变量的查询如下:

SELECT _pk FROM FinancialDetail 
WHERE   ( Field01 = @Field01 OR ( Field01 IS NULL AND @Field01 IS NULL ) )
    AND ( Field02 = @Field02 OR ( Field02 IS NULL AND @Field02 IS NULL ) )
    AND ( Field03 = @Field03 OR ( Field03 IS NULL AND @Field03 IS NULL ) )
    AND ( Field04 = @Field04 OR ( Field04 IS NULL AND @Field04 IS NULL ) )
    AND ( Field05 = @Field05 OR ( Field05 IS NULL AND @Field05 IS NULL ) )
    AND ( Field06 = @Field06 OR ( Field06 IS NULL AND @Field06 IS NULL ) )
    AND ( Field07 = @Field07 OR ( Field07 IS NULL AND @Field07 IS NULL ) )
    AND ( Field08 = @Field08 OR ( Field08 IS NULL AND @Field08 IS NULL ) )
    AND ( Field09 = @Field09 OR ( Field09 IS NULL AND @Field09 IS NULL ) )
    AND ( Field10 = @Field10 OR ( Field10 IS NULL AND @Field10 IS NULL ) )
    AND ( Field11 = @Field11 OR ( Field11 IS NULL AND @Field11 IS NULL ) )
    AND ( Field12 = @Field12 OR ( Field12 IS NULL AND @Field12 IS NULL ) )
    AND ( Field13 = @Field13 OR ( Field13 IS NULL AND @Field13 IS NULL ) )
    AND ( Field14 = @Field14 OR ( Field14 IS NULL AND @Field14 IS NULL ) )
    AND ( Field15 = @Field15 OR ( Field15 IS NULL AND @Field15 IS NULL ) )
    AND ( Field16 = @Field16 OR ( Field16 IS NULL AND @Field16 IS NULL ) )
    AND ( Field17 = @Field17 OR ( Field17 IS NULL AND @Field17 IS NULL ) )
    AND ( Field18 = @Field18 OR ( Field18 IS NULL AND @Field18 IS NULL ) )
    AND ( Field19 = @Field19 OR ( Field19 IS NULL AND @Field19 IS NULL ) )
    AND ( Field20 = @Field20 OR ( Field20 IS NULL AND @Field20 IS NULL ) )
    AND ( Field21 = @Field21 OR ( Field21 IS NULL AND @Field21 IS NULL ) )
    AND ( Field22 = @Field22 OR ( Field22 IS NULL AND @Field22 IS NULL ) )
    AND ( Field23 = @Field23 OR ( Field23 IS NULL AND @Field23 IS NULL ) )
    AND ( Field24 = @Field24 OR ( Field24 IS NULL AND @Field24 IS NULL ) )
    AND ( Field25 = @Field25 OR ( Field25 IS NULL AND @Field25 IS NULL ) )
    AND ( Field26 = @Field26 OR ( Field26 IS NULL AND @Field26 IS NULL ) )
    AND ( Field27 = @Field27 OR ( Field27 IS NULL AND @Field27 IS NULL ) )
    AND ( Field28 = @Field28 OR ( Field28 IS NULL AND @Field28 IS NULL ) )
    AND ( Field29 = @Field29 OR ( Field29 IS NULL AND @Field29 IS NULL ) )
    AND ( Field30 = @Field30 OR ( Field30 IS NULL AND @Field30 IS NULL ) )
    AND ( Field31 = @Field31 OR ( Field31 IS NULL AND @Field31 IS NULL ) )
    AND ( Field32 = @Field32 OR ( Field32 IS NULL AND @Field32 IS NULL ) )
    AND ( Field33 = @Field33 OR ( Field33 IS NULL AND @Field33 IS NULL ) )
    AND ( Field34 = @Field34 OR ( Field34 IS NULL AND @Field34 IS NULL ) )
    AND ( Field35 = @Field35 OR ( Field35 IS NULL AND @Field35 IS NULL ) )
    AND ( Field36 = @Field36 OR ( Field36 IS NULL AND @Field36 IS NULL ) )
    AND ( Field37 = @Field37 OR ( Field37 IS NULL AND @Field37 IS NULL ) )
    AND ( Field38 = @Field38 OR ( Field38 IS NULL AND @Field38 IS NULL ) )
    AND ( Field39 = @Field39 OR ( Field39 IS NULL AND @Field39 IS NULL ) )
    AND ( Field40 = @Field40 OR ( Field40 IS NULL AND @Field40 IS NULL ) )

2 个答案:

答案 0 :(得分:3)

这不是动态搜索。正在比较所有列。在不改变语义的情况下删除任何内容都是不可能的。

Field01 = @Field01 OR ( Field01 IS NULL AND @Field01 IS NULL ) 

只是意味着两个Null比较相等的两者都相等。此模式通常不会导致SQL Server出现任何问题。减少的例子是

CREATE TABLE #FinancialDetail
(
_pk INT PRIMARY KEY,
Field01 INT,
Field02 INT,
Field03 INT
)
CREATE INDEX IX ON #FinancialDetail(Field01, Field02, Field03)

declare @Field01 int, @Field02 int, @Field03 int;

SELECT _pk FROM #FinancialDetail 
WHERE   ( Field01 = @Field01 OR ( Field01 IS NULL AND @Field01 IS NULL ) )
    AND ( Field02 = @Field02 OR ( Field02 IS NULL AND @Field02 IS NULL ) )
    AND ( Field03 = @Field03 OR ( Field03 IS NULL AND @Field03 IS NULL ) )

显示所有三列的索引搜索

enter image description here

事实上,这个计划与

无法区分
SELECT _pk FROM #FinancialDetail 
WHERE   ( Field01 = @Field01 )
    AND ( Field02 = @Field02 )
    AND ( Field03 = @Field03 )

索引查找中的相等运算符对NULL使用不同的语义这一事实并未向我们as discussed in the comments here公开。

您需要在一些相当有选择性的列组合上使用复合索引(SQL Server最多允许16个键列),并且应该能够对其进行搜索。

如果您需要使用现有的单列索引,并且最佳值可能会有所不同,则可以添加OPTION (RECOMPILE)

您还可以重写如下,这是更短和相同的语义,但我怀疑它会对计划产生任何影响。

SELECT _pk FROM #FinancialDetail 
WHERE EXISTS (SELECT @Field01, @Field02, @Field03 /*.... , @Field40*/
              INTERSECT
              SELECT Field01, Field02, Field03 /*.... , Field40*/ )

答案 1 :(得分:1)

评论有点长。我猜测10条件让优化器混乱。你有一个复杂的(尽管是重复的)OR条件。

一个大问题是SQL Server缓存执行计划,因此第一次运行查询时,会设置计划。如果以后的值可能更好地使用索引,则不一定会使用它们。

我建议使用动态SQL来消除WHERE条件。产生的条件取决于变量的值。如果OR@Field02@Field03,则条件如下:

NULL

这些是具有相等性的严格WHERE ( Field01 = @Field01 ) AND ( Field02 IS NULL ) AND ( Field03 IS NULL ) AND ( Field04 = @Field04 ) AND . . . 条件,优化器应该更容易处理。