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并在合并结果之前完全评估两个谓词。

也就是说,如果优化器可以在编译时确定一个谓词将始终计算为TRUEFALSE ,那么优化器应该将其视为一个常量。 因此,例如,如果在表上存在一个约束来阻止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) 

无论优化器对ANDOR可能做什么或不可以做什么,如果出于任何原因必须强制执行特定的评估顺序,则可以使用其他保证短路评估的工具重写查询。

例如:

 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条件。