Использует ли Oracle оценку короткого замыкания?
У меня есть запрос 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)
Ответы
Ответ 1
Это зависит.
,
В общем, Oracle не гарантирует, что оператор SQL будет использовать оценку короткого замыкания (хотя PL/SQL гарантированно выполняет оценку короткого замыкания). Оптимизатор Oracle может свободно оценивать предикаты в любом порядке, который, как ожидается, будет наиболее эффективным. Это может означать, что первый предикат сначала оценивается, и только соответствующие строки оценивают второй предикат, но вполне возможно, что либо происходит обратное, либо что Oracle преобразует запрос в вид UNION
и полностью оценивает оба предиката перед объединением результаты.
При этом, если оптимизатор может определить во время компиляции, что предикат всегда будет оценивать до TRUE
или FALSE
, оптимизатор должен просто рассматривать это как константу. Так, если, например, существует ограничение на таблицу, которое предотвращает X
от когда-либо имеющего значение "true", оптимизатор не должен вообще оценивать второй предикат (хотя разные версии оптимизатора будут иметь разные возможности чтобы обнаружить, что что-то является константой во время компиляции).
Что касается второй части вашего вопроса, не видя планов запросов, это очень сложно сказать. Оптимизатор Oracle, как правило, очень хорош в преобразовании запросов из одной формы в другую, если есть более эффективные способы ее оценки. В общем случае, однако, если subQ
вернет относительно большое количество строк по сравнению с table
, может быть более эффективным структурировать запрос как EXISTS
, а не как IN
.
Ответ 2
Предостережение: Oracle не является моей основной областью знаний.
Оптимизатор, основанный на затратах, должен знать, что стоимость X = 'true'
меньше, чем подзапрос, поэтому он, скорее всего, сначала оценит более простой вариант. Но условия AND и OR в SQL не являются короткозамкнутыми, как &&
и ||
находятся в C и его производных.
Подзапрос может быть одной из двух форм: коррелированный и некоррелированный.
- Корректированный подзапрос должен выполняться много раз (поэтому он опасен для производительности), потому что корреляция означает, что результат суб-запроса каким-то образом зависит от строки "в настоящее время оценивается" ).
- Некорректированный подзапрос будет выполняться только один раз.
Пример коррелированного подзапроса:
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)
Ответ 3
Независимо от того, что оптимизатор может или не может делать с AND
и OR
, если по какой-либо причине вы должны выполнить конкретный порядок оценки, вы можете переписать запрос, используя другие инструменты, где оценка короткого замыкания гарантируется.
Например:
select * from table 1
where case when X = 'true' then 1
when Y in (select ....) then 1
end = 1
Если X является "истинным", тогда выражение case оценивается в 1, второе "когда" пропускается и условие оценивается как "ИСТИНА". Если X не является "истинным", тогда выполняется условие IN.