Oracle10g 有人能帮我弄明白Oracle';s(10g)和/或短路?

Oracle10g 有人能帮我弄明白Oracle';s(10g)和/或短路?,oracle10g,short-circuiting,Oracle10g,Short Circuiting,考虑以下查询并注意CALCULATE_激励函数: SELECT EMP.* FROM EMPLOYEES EMPS WHERE EMP.STATUS = 1 AND EMP.HIRE_DATE > TO_DATE('1/1/2010') AND EMP.FIRST_NAME = 'JOHN' AND CALCULATE_INCENTIVE(EMP.ID) > 1000 ORDER BY EMPS.ID DESC; 我的印象是Oracle使用了与.NE

考虑以下查询并注意CALCULATE_激励函数:

SELECT EMP.* FROM EMPLOYEES EMPS
WHERE
    EMP.STATUS = 1 AND
    EMP.HIRE_DATE > TO_DATE('1/1/2010') AND
    EMP.FIRST_NAME = 'JOHN' AND
    CALCULATE_INCENTIVE(EMP.ID) > 1000
ORDER BY EMPS.ID DESC;
我的印象是Oracle使用了与.NET在其and/or逻辑中使用的相同(或类似)短路。例如,如果EMP.STATUS=2,它将不需要计算表达式的其余部分,因为整个表达式将返回false

在我的例子中,CALCULATE_激励函数是对db中的每个员工调用的,而不仅仅是前三个WHERE表达式返回的9条记录。我甚至试着在我想分组进行短路计算的特定表达式周围加上括号,但我想不出来


如果前面的任何表达式返回false,有没有人知道如何让CALCULATE\u INCENTIVEnot进行评估?

一种方法是将主要条件放入Oracle无法优化的子查询中,然后将次要条件放入外部查询中。确保Oracle不会优化子查询的最简单方法是在select语句中包含rownum:

SELECT * FROM (
   SELECT EMP.*, ROWNUM 
   FROM EMPLOYEES EMPS
   WHERE
       EMP.STATUS = 1
       AND EMP.HIRE_DATE > TO_DATE('1/1/2010')
       AND EMP.FIRST_NAME = 'JOHN')
WHERE CALCULATE_INCENTIVE(ID) > 1000
ORDER BY EMPS.ID DESC;

Oracle支持PL/SQL中的短路评估。然而,在SQL中,优化器可以自由地按照它希望的任何顺序计算谓词,将谓词推送到视图和子查询中,或者在它认为合适的情况下转换SQL语句。这意味着您不应该依赖于以特定顺序应用的谓词,并且使顺序谓词出现在WHERE子句中基本上是不相关的。可用的索引、存在的优化器统计信息、优化器参数和系统统计信息都比WHERE子句中谓词的顺序重要得多

例如,在PL/SQL中,您可以用一个函数来演示这一点,该函数在实际调用时抛出一个错误

SQL> ed
Wrote file afiedt.buf

  1  create function throw_error( p_parameter IN NUMBER )
  2    return number
  3  as
  4  begin
  5    raise_application_error( -20001, 'The function was called' );
  6    return 1;
  7* end;
SQL> /

Function created.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_num NUMBER;
  3  begin
  4    l_num := 1;
  5    if( l_num = 2 and throw_error( l_num ) = 2 )
  6    then
  7      null;
  8    else
  9      dbms_output.put_line( 'Short-circuited the AND' );
 10    end if;
 11    if( l_num = 1 or throw_error( l_num ) = 2 )
 12    then
 13      dbms_output.put_line( 'Short-circuited the OR' );
 14    end if;
 15* end;
 16  /
Short-circuited the AND
Short-circuited the OR

PL/SQL procedure successfully completed.

另一方面,在SQL中,操作顺序由优化器决定,而不是由您决定,因此优化器可以随意短路或不短路。乔纳森·根尼克(Jonathan Gennick)有一篇很棒的文章详细讨论了这一点。在您的特定情况下,如果您有一个关于(名字、雇用日期、状态)的复合索引以及适当的统计数据,那么优化器几乎肯定会使用该索引来评估前三个条件,然后只为满足其他三个条件的ID调用
计算激励
函数。如果您在
计算激励(id)
上创建了基于函数的索引,那么优化器可能会使用该索引,而不是在运行时调用该函数。但是,如果优化器认为这样做效率更高,那么它可以完全自由地决定为每一行调用函数。

有趣的是,您提出了这个答案,因为这是我昨天问的一个问题中给出的解决方案,也是我采取的最终路线。不过,我知道Oracle支持短路评估,我很想弄清楚它是如何工作的。@oscilatingcretin:这个解决方案在我脑海中很新鲜,因为我最近才写过它。对不起,我不知道手术是一样的。不过,据我所知,这是迫使Oracle以特定方式中断评估的唯一方法。正如@Justin Cave所指出的,Oracle将短路条件,但它是基于优化器的路径,而不是查询的语法。