Oracle10g 有人能帮我弄明白Oracle';s(10g)和/或短路?
考虑以下查询并注意CALCULATE_激励函数: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
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将短路条件,但它是基于优化器的路径,而不是查询的语法。