我难以理解某些运算符优先级,因此我期望下面的 all 所有查询失败;这是基于下面的文档,在该文档中,将在比较运算符之前评估除法。
t-sql运算符优先级的Microsoft文档:https://docs.microsoft.com/en-us/sql/t-sql/language-elements/operator-precedence-transact-sql?view=sql-server-2017
样本数据和查询
CREATE TABLE #orders(
price INT
)
GO
INSERT INTO #orders VALUES
(1)
,(2)
,(3)
,(4)
,(5)
,(6)
,(7)
,(8)
,(9)
,(10)
,(0)
GO
/*
the following two queries work
*/
SELECT *
FROM #orders
WHERE 2 / price > 0
AND price > 0;
SELECT *
FROM #orders
WHERE price > 0
AND 2 / price > 0;
/*
these don't work - getting divide by zero error
*/
SELECT *
FROM #orders
WHERE 2 / price > 0
AND price IN ( 1, 2, 3, 4,
5, 6, 7, 8,
9, 10 );
SELECT *
FROM #orders
WHERE price IN ( 1, 2, 3, 4,
5, 6, 7, 8,
9, 10 )
AND 2 / price > 0;
其中一个工作查询的共享执行计划:https://www.brentozar.com/pastetheplan/?id=HJFH3JWB7
其中一个无效查询的共享(估计)执行计划:https://www.brentozar.com/pastetheplan/?id=r1Ds2yWSQ
在理解这种行为方面的任何帮助将不胜感激!
谢谢
Eli
答案 0 :(得分:3)
好问题。我认为documentation page that you shared上的语言可能不太准确,可能会引起您的困惑。这是一个引号(强调我的意思):
当复杂表达式具有多个运算符时,运算符优先级 确定执行操作的顺序。的 执行顺序会严重影响结果值。
这里的强烈含义是优先级和执行顺序本质上是同一件事,但事实并非如此。 Eric Lippert explains this比以往任何时候都好(强调原文)。
优先级规则描述了带括号的表达式应如何使用 当表达式混合使用不同类型的 运算符。例如,乘法的优先级高于 另外,因此2 + 3 x 4等于2 +(3 x 4),而不是(2 + 3)x 4。
关联性规则描述了带括号的表达式 当表达式具有一堆相同的表达式时,应将其括起来 一种操作员。例如,加法从左到右是关联的 对,所以a + b + c等于(a + b)+ c,而不是a +(b + c)。在 普通的算术,这两个表达式总是给出相同的 结果;在计算机算术中,它们不一定。 (作为一个 运动可以找到a,b,c的值,使得(a + b)+ c为 不等于C#中的+(b + c)?)
现在这令人困惑。
求值顺序规则描述了每个操作数在其中的顺序 计算表达式。括号只是描述了 结果分组在一起; “先做括号”不是规则 C#。相反,C#中的规则是“严格评估每个子表达式 从左到右”。
阅读全部内容。埃里克(Eric)使用C#和C ++作为示例,但是他的注释比这更广泛地适用。正如他的建议,如果您将运算符优先级规则视为控制表达式组成部分的分组方式,而不是控制它们执行的顺序,那么您所看到的行为就更有意义了。这是您可以理解会失败但实际上成功的查询之一的简化版本:
declare @t table (x int);
insert @t values (0);
select * from @t where 2 / x > 0 and x > 0;
SQL Server的运算符优先级规则仅表示上述查询等效于:
-- Same query as above with operator precedence shown explicitly.
select * from @t where ((2 / x) > 0) and (x > 0);
在这种情况下,关于AND
的有趣之处在于,如果您知道它的一个操作数为false,那么您就知道整个表达式为false,甚至不计算另一个操作数。一些编程语言指定了操作数求值的顺序。例如,the && operator in C#首先评估其左操作数,如果为假,则根本不评估其右操作数。但是AND
operator in T-SQL没有一种或另一种主张;由优化器选择。
有很多文章专门探讨这种行为;例如here is a pretty detailed one。这有帮助吗?
答案 1 :(得分:1)
我认为这与运算符的优先级无关,但是优化程序选择哪种顺序来评估where子句。
在前两行中,必须where price > 0
首先过滤行,以防止错误。
由于后两个使用IN
,因此必须首先进行除法以限制行,然后评估IN
过滤器。可以通过添加索引来防止这种情况...即使ID
为主键,该键创建聚簇索引,并且由于优化器可以使用索引并在除法之前对行进行过滤,因此不会出现错误,或选择。
谓词应从price > 0 AND 2 / price > 0
更改为2/price > 0
答案 2 :(得分:0)
实际上,我更喜欢更改表达式(不太可能拥有价格指数-或简单地使带有或不带有索引的价格都健壮起来):
#box