Oracle использует оценку короткого замыкания? - PullRequest
16 голосов
/ 17 января 2012

У меня есть запрос Oracle, который структурирован следующим образом:

SELECT   *
FROM     table
WHERE    X='true' OR
         Y IN (complicated subquery)

Если Oracle увидит, что X равен «true», он все равно попытается оценить часть Y IN (подзапрос) предложения WHERE? Кроме того, в таком выражении такой подзапрос будет выполняться несколько раз для каждой записи в таблице? Буду ли я лучше с чем-то вроде:

WITH subQ as (complicated subquery)
SELECT   *
FROM     table
WHERE    X='true' OR
         Y IN (SELECT id FROM subQ)

Ответы [ 4 ]

31 голосов
/ 17 января 2012

Это зависит. , В целом, Oracle не гарантирует, что в операторе SQL будет использоваться оценка короткого замыкания (хотя PL / SQL гарантированно выполняет оценку короткого замыкания). Оптимизатор Oracle может свободно оценивать предикаты в любом порядке, который он ожидает, чтобы быть наиболее эффективным. Это может означать, что первый предикат оценивается первым, и только второй совпадающий ряд оценивается вторым предикатом, но вполне возможно, что произойдет обратное или Oracle преобразует запрос в вид UNION и полностью оценивает оба предиката перед объединением результаты.

При этом, если оптимизатор может определить во время компиляции, что предикат всегда будет иметь значение TRUE или FALSE, оптимизатор должен просто воспринимать это как константу. Так, если, например, в таблице есть ограничение, которое не позволяет X иметь значение 'true', оптимизатор вообще не должен оценивать второй предикат (хотя разные версии оптимизатора будут иметь разные возможности) обнаружить, что что-то является константой во время компиляции).

Что касается второй части вашего вопроса, то, не видя планов запросов, очень трудно сказать. Оптимизатор Oracle, как правило, хорошо умеет преобразовывать запросы из одной формы в другую, если существуют более эффективные способы ее оценки. В общем, однако, если subQ собирается вернуть относительно большое количество строк по сравнению с table, может быть более эффективно структурировать запрос как EXISTS, а не как IN.

12 голосов
/ 17 января 2012

Предостережение : Oracle не является моей основной областью знаний.

Оптимизатор на основе стоимости должен знать, что стоимость X = 'true' меньше подзапроса, поэтому он, скорее всего, сначала оценит более простую альтернативу. Но условия И и ИЛИ в SQL являются не короткозамкнутыми, как && и || в С и его производных.

Подзапрос может иметь одну из двух форм: коррелированную и некоррелированную.

  • Коррелированный подзапрос должен выполняться много раз (именно поэтому они опасны для производительности), потому что корреляция означает, что результат подзапроса зависит в некоторой степени от строки «в настоящее время оценивается»).
  • Некоррелированный подзапрос будет выполнен только один раз.

Пример коррелированного подзапроса:

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)
1 голос
/ 01 ноября 2018

Я пришел сюда в поисках ответа о том, как избежать сбоя с помощью оценки короткого замыкания.В итоге я получил работу:

...
where case when [its not going to crash] 
           then [short circuit expression] 
           else [safe, never used value] 
       end = comparison_value
...

Так, например, если вы беспокоитесь о сбое выражения to_number, вы должны поместить что-то вроде "REGEXP_LIKE (my_possible_number, '^ [[: digit:]]+ $ ') "в предложении when (для положительных целых чисел - скорректировать на неположительное или нецелое).

1 голос
/ 15 декабря 2016

Независимо от того, что оптимизатор может или не может делать с AND и OR, если по какой-либо причине вы должны применить определенный порядок оценки, вы можете переписать запрос, используя другие инструменты, где оценка короткого замыкания гарантируется.

Например:

select * from table 1
where case when X = 'true' then 1
           when Y in (select ....)   then 1
      end  = 1

Если X равен 'true', тогда выражение case оценивается как 1, второе «когда» пропускается, а условие оценивается как TRUE. Если X не «истина», то условие IN оценивается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...