Может ли кто-нибудь помочь мне определить короткое замыкание Oracle (10g) И / ИЛИ? - PullRequest
2 голосов
/ 17 июня 2011

Рассмотрим следующий запрос и обратите внимание на функцию CALCULATE_INCENTIVE:

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 в своей и / или логике. Например, если EMP.STATUS = 2, он не будет беспокоиться об оценке остальной части выражения, поскольку все выражение в любом случае вернет false.

В моем случае функция CALCULATE_INCENTIVE вызывается для каждого сотрудника в БД, а не только для 9 записей, которые возвращают первые три выражения WHERE. Я даже пытался поместить скобки вокруг определенных выражений, которые я хочу сгруппировать для оценки короткого замыкания, но я не могу понять это.

У кого-нибудь есть идеи, как получить оценку CALCULATE_INCENTIVE , а не , если какое-либо из предыдущих выражений вернет false?

Ответы [ 2 ]

2 голосов
/ 17 июня 2011

Один из способов - поместить первичные критерии в подзапрос, который Oracle не может оптимизировать, а затем поместить вторичные критерии во внешний запрос. Самый простой способ убедиться, что Oracle не оптимизирует подзапрос, - включить rownum в оператор select:

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;
1 голос
/ 17 июня 2011

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, с другой стороны, порядок операций определяется оптимизатором, а не вами, поэтому оптимизаторсвободен от короткого замыкания или нет, как он хочетУ Джонатана Дженника есть отличная статья Subquery Madness! , в которой это обсуждается довольно подробно.В вашем конкретном случае, если у вас есть составной индекс (FIRST_NAME, HIRE_DATE, STATUS) вместе с соответствующей статистикой, оптимизатор почти наверняка будет использовать индекс для оценки первых трех условий, а затем вызовет только функцию CALCULATE_INCENTIVE для идентификаторов.что соответствует другим трем критериям.Если вы создадите индекс на основе функции в CALCULATE_INCENTIVE(id), оптимизатор, скорее всего, будет использовать его, а не вызывать функцию вообще во время выполнения.Но оптимизатор был бы совершенно свободен, чтобы решить вызывать функцию для каждой строки в любом случае, если бы он решил, что это будет более эффективно сделать.

...