Oracle, вероятно, применяет неверное преобразование оптимизатора, превращая три запроса, которые выполняются быстро независимо, в один запрос, который выполняется медленно. Самый простой способ отключить эти преобразования и убедиться, что каждый запрос выполняется сам по себе, - добавить на первый взгляд бесполезное условие ROWNUM
, например:
with datasetA as (... where rownum >= 1),
datasetB as (... where rownum >= 1),
datasetC as (... where rownum >= 1)
select a.*
from datasetA a
join datasetB b on b.key = a.key
join datasetC c on c.key = a.key;
Псевдостолбец ROWNUM
предназначался для составления отчетов топ-N, что не сработало бы, если бы Oracle переписывал каждый запрос. Таким образом, оптимизатор оставляет эти подзапросы в покое, даже если условие логически избыточно.
Выше приведен простой способ решения насущной проблемы, но не обязательно лучший. Возможно, вы захотите выяснить, почему Oracle выбирает плохие преобразования;плохая статистика оптимизатора часто является виновником. Поиск основной причины может помочь решить другие проблемы, но может быть трудным процессом.
Если вам интересно почему Oracle делает это, преобразования оптимизатора часто бывают полезными. Преобразования, такие как слияние представлений и передача предикатов, позволяют Oracle применять знания из одной части запроса к другой, что часто значительно улучшает время выполнения. Например, представьте запрос типа select * from (select * from huge_table) where primary_key = 1;
. Мы, конечно, хотели бы, чтобы этот предикат был вставлен в подзапрос, поэтому Oracle не нужно читать всю таблицу, чтобы получить только одну строку.