系统是: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,则无需添加最小值 对查询的级别限制以及为该操作保存比较运算符(假设级别上没有索引)
我得到的实际上是一个更长的查询,或者至少不是一个比“未优化”查询更短的查询。
任何人都可以解释原因吗?
答案 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
我们不再有明确的起点。数据库无法确定从中开始结果的特定行。为了确定要返回的记录,必须检查每个行以确保它符合您的要求。如果匹配,则将该行添加到其结果中并移至下一行。