如何评估SQL OR运算符

时间:2011-01-27 11:39:06

标签: sql query-optimization sql-server-2008-r2

系统是:SQL Server 2008-R2

我有一个表,其中一列是名为“Level”的tinyint。 等级是非负数。

当我这样做时:

SELECT XXXXX
FROM   YYYYY
WHERE ( ------------ ) AND 
      (Level >= @MinLevel) AND
      ( ------------ )

我得到了正确的答复。

为了优化查询,我试着这样做:

SELECT XXXXX
FROM   YYYYY
WHERE ( ------------ ) AND 
      ((@MinLevel = 0) OR (Level >= @MinLevel)) AND
      ( ------------ )

如果请求的最低级别为0,则无需添加最小值 对查询的级别限制以及为该操作保存比较运算符(假设级别上没有索引)

我得到的实际上是一个更长的查询,或者至少不是一个比“未优化”查询更短的查询。

任何人都可以解释原因吗?

3 个答案:

答案 0 :(得分:2)

问题是sql-server-2008-r2,所以我们不会考虑其他DBMS。

在这里查看一些深入分析:http://www.sommarskog.se/dyn-search-2008.html

它讨论了许多执行动态搜索的方法,这些方法与问题有些相关。特别是这句话:

  

所有@x IS NULL的效果   条款就是那个输入   参数是NULL,那么   AND条件总是正确的。的因此,   唯一有效的条件   是那些搜索参数   具有非NULL值。

     

....而且表现如何? 非常好   只要包含查询提示即可   选项(重建)。

这可以在Static SQL部分找到,适用于 SQL 2008 R2 CU1 (10.50.1702) or later

使用OPTION(RECOMPILE)提示将相同的优化快捷方式(仅在(@MinLevel = 0)评估RHS时)应用于您的查询。

(注意到这个问题已在评论中提出)

答案 1 :(得分:0)

OR子句未经过优化(几乎在任何DBMS中)。 例如,这意味着将忽略索引,并且两个案例都必须进行评估

直> =只是一个直接比较

答案 2 :(得分:0)

OR操作员通常会抛出窗口索引。

想象一下,你有一个带有索引id列的表,每列计数一次。在此表中,您有100行。第1行在此列中的值为1,第100行的值为100.

现在运行此查询: SELECT * FROM table WHERE column> = 45

此查询有一个明确的起点:45

所以它检查的第一个记录正好在你的表中间,列值为50.这对于45来说太高了,但它已经消除了一半的表,它不需要看在。然后它将查看该组中间的记录,该值为25.这太低了,但它又消除了一半的结果。

长话短说,为了找到第45个,它只需要看6到7行。然后它会为您提供从那里到表末尾的每一行作为结果集。

现在让我们调整一下这个查询: SELECT * FROM table WHERE column> = 45 OR column = 43

我们不再有明确的起点。数据库无法确定从中开始结果的特定行。为了确定要返回的记录,必须检查每个行以确保它符合您的要求。如果匹配,则将该行添加到其结果中并移至下一行。