Oracle是否使用短路评估?
我有一个Oracle查询结构如下:
SELECT * FROM table WHERE X='true' OR Y IN (complicated subquery)
如果Oracle看到X确实等于“真”,它是否仍然尝试评估WHERE子句的Y IN(子查询)部分? 另外,在这样的陈述中,子查询是否会对表中的每个条目执行多次? 我是否会变得更好:
WITH subQ as (complicated subquery) SELECT * FROM table WHERE X='true' OR Y IN (SELECT id FROM subQ)
这取决于。 。 一般来说,Oracle不保证SQL语句将使用短路评估(尽pipePL / SQL保证执行短路评估)。 Oracle优化器可以按照预期的最有效的顺序自由地评估谓词。 这可能意味着首先评估第一个谓词,而只有匹配的行才会评估第二个谓词,但是完全可能发生相反的情况,或者Oracle将查询转换为某种UNION
并在合并结果之前完全评估两个谓词。
也就是说,如果优化器可以在编译时确定一个谓词将始终计算为TRUE
或FALSE
,那么优化器应该将其视为一个常量。 因此,例如,如果在表上存在一个约束来阻止X
具有“true”值,那么优化器根本不应该评估第二个谓词(尽pipe不同版本的优化器将具有不同的检测能力在编译时某事是一个常数)。
至于你的问题的第二部分,没有看到查询计划,这是很难说的。 如果有更有效的评估方法,Oracle优化器在将查询从一种forms转换为另一种forms方面往往是相当不错的。 但是,一般来说,如果subQ
将返回与table
相比相对较多的行,将查询构造为EXISTS
而不是IN
可能更有效。
警告 :Oracle不是我的主要专业领域。
基于成本的优化器应该知道X = 'true'
的成本小于子查询,所以它可能首先评估更简单的select。 但是SQL中的AND和OR条件并不像&&
和||
那样短路 在C及其衍生物。
子查询可以是两种forms之一:相关和不相关。
- 相关的子查询必须执行多次(这就是为什么它们对性能有危险的原因),因为相关性意味着子查询结果在某些方面取决于当前正在评估的行。
- 一个不相关的子查询只能执行一次。
示例相关的子查询:
SELECT * FROM Table1 WHERE X = 'true' OR Y IN (SELECT Z FROM Table2 WHERE Table2.A = Table1.B)
示例非相关子查询:
SELECT * FROM Table1 WHERE X = 'true' OR Y IN (SELECT Z FROM Table2 WHERE Table2.A > 13)
无论优化器对AND
和OR
可能做什么或不可以做什么,如果出于任何原因必须强制执行特定的评估顺序,则可以使用其他保证短路评估的工具重写查询。
例如:
select * from table 1 where case when X = 'true' then 1 when Y in (select ....) then 1 end = 1
如果X为“真”,那么caseexpression式的计算结果为1,第二个“when”被跳过,条件计算结果为TRUE。 如果X不是“真”,则评估IN条件。