Update 11/2Oracle 12c Подзапрос Факторинг Inline View теперь имеет плохой план?
После некоторых дополнительных поиска и устранения неисправностей, моя команда была в состоянии связать эту ошибку Oracle непосредственно к изменению параметра, который был сделан на базе 12c
ночи перед запрос перестал работать. После некоторых проблем с производительностью из приложения, привязанного к этой базе данных, моя команда изменила наш DBA параметр OPTIMIZER_FEATURES_ENABLE
с 12.1.02
на 11.2.0.4
. Это устранило проблему производительности для проблемного приложения, но вызвало ошибку, описанную выше. Чтобы проверить, я смог воспроизвести эту же проблему в отдельной среде, изменив этот параметр. Мой DBA подал билет с Oracle, чтобы это выглядело.
В качестве обходного пути я смог внести небольшое изменение в свой запрос, чтобы получить ожидаемые результаты. В частности, я объединил Subquery1
с Subquery2
, и я переместил несколько предикатов в Subquery1
из предложения WHERE
в JOIN
(где они более правильно принадлежали). Это изменение изменило мой план выполнения (он немного менее эффективен, чем тот, который был указан ранее), но этого было достаточно для решения исходной проблемы.
Оригинал Сообщение
Во-первых, позвольте мне извиниться за любую неясность в этом вопросе, но я имею дело с конфиденциальной финансовой системой, поэтому я вынужден скрывать определенные детали реализации.
фон
У меня есть Oracle
запрос, который я положил в производство давно, что в последнее время перестали производить ожидаемые результаты по совпадению после обновления от 11g
до 12c
. По моему (и моей команде поддержки поддержки) этот запрос работал нормально уже более года до этого.
Деталь
Запрос является слишком сложным и не очень эффективным, но это в значительной степени потому, что я имею дело с не нормированными таблицами (исторически смоделированным после мэйнфреймов) и плохого вводом данных из добывающих систем. Чтобы справиться со сложной ситуацией в бизнесе, я использовал несколько уровней подзапроса факторинга (оператор WITH
), а затем мое заключительное заявление объединяет два встроенных представления. Основная структура запроса без всех сложных предикатов выглядит следующим образом:
У меня есть 3 таблицы Table1
, Table2
, Table3
. Table1
- таблица обработки, составленная из записей от Table2
.
--This grabs a subset from Table1
WITH Subquery1 as (
SELECT FROM Table1),
--This eliminates certain records from the first subset based on sister records
--from the original source table
Subquery2 as (
SELECT FROM Subquery1
WHERE NOT EXISTS FROM (SELECT from Table2)),
--This ties the records from Subquery2 to Table3
Subquery3 as (
SELECT FROM Table3
JOIN (SELECT Max(Date) FROM Table3)
JOIN Subquery2)
--This final query evaluates subquery3 in two different ways and
--only takes those records which fit the criteria items from both sets
SELECT FROM
(SELECT FROM Subquery3) -- Call this Inline View A
JOIN (SELECT FROM Subquery3) -- Call this Inline View B
окончательный запрос довольно простой:
SELECT A.Group_No, B.Sub_Group, B.Key, B.Lob
FROM (SELECT Group_No, Lob, COUNT(Sub_Group)
FROM Subquery3
GROUP BY Group_No, Lob
HAVING COUNT(Sub_Group) = 1) A
JOIN (SELECT Group_No, Sub_Group, Key, Lob
FROM Subquery3
WHERE Sub_Group LIKE '0000%') B
ON A.Group_No = B.Group_No
AND A.Lob = B.Lob
Проблема
Если отредактировать окончательный запрос, чтобы удалить второй Инлайн View и оценить выход A
инлайн взгляд, я ухожу с 0 возвращенных строк. Я вручную оценил записи для каждого отдельного подзапроса и могу подтвердить, что это ожидаемый результат.
Аналогичным образом, если я отредактирую окончательный запрос, чтобы произвести вывод только встроенного представления «B», я ухожу с 6 возвращенных строк. Опять же, я вручную оценил данные, и это точно так, как ожидалось.
Теперь, когда мы соединяем эти два подмножества (Inline View A
и Inline View B
), я ожидаю, что итоговый результат запроса будет 0 строк (так как внутреннее соединение между полным набором и пустым набором не дает совпадений) , Однако, когда я запускаю весь запрос с внутренним соединением, как описано выше, Я возвращаюсь 1158 строк!
Я рассмотрел план выполнения, но ничего не выскакивает на меня:
Вопросы
Очевидно, что я сделал что-то, чтобы запутать Oracle Optimizer и обновленный план запроса отбрасывает гораздо другой запрос, чем тот, который я представил. Мое лучшее предположение заключается в том, что со всеми этими временными представлениями, плавающими внутри одного и того же запроса, я запутал Oracle в оценке некоторого набора до того, на что он зависит.
До сих пор я не смог найти официальную документацию Oracle вокруг инструкции WITH
, поэтому я никогда не был полностью уверен в том, что порядок подзапросов оценивается. Я заметил, что в поиске SO (не может найти его сейчас), кто-то сказал, что факторизованный подзапрос не может ссылаться на другой факторизованный запрос. Я никогда раньше не знал, что это правда, но причудливый вывод выше заставляет меня задаться вопросом, не дождался ли я раньше этого вопроса?
Может ли кто-нибудь объяснить поведение, которое я вижу? Я пытаюсь сделать что-то явно неправильное с этим планом запроса? Или, альтернативно, есть ли вероятность, что что-то изменилось между 11g и 12c, что может объяснить, почему поведение этого запроса могло измениться?
Привет, - Абсолютно факторизованный подзапрос CAN может ссылаться на другой (всегда определенный перед ним), я использую это все время в довольно сложных комбинациях, и он никогда не терпит неудачу, как в 11.2, так и 12.1. Тогда - многое другое может измениться между версиями Oracle; правило, которое ранее не применялось, или они улучшают реализацию, но вы сталкиваетесь с ситуацией, когда они не тестировали, где они что-то сломали, что происходит все время. Вы можете рассмотреть возможность публикации в OTN, есть несколько экспертов по оптимизации, которые не посещают SO, если вообще. Удачи! – mathguy
Или, действительно, ничего себе, теперь, когда я прочитал полный вопрос - у вас не просто проблема с эффективностью, у вас также есть логическая проблема. Это гораздо более вероятно, чтобы выявить ошибку в коде, а не Oracle что-то сломать. Поскольку вы не можете использовать код для очевидной причины защиты бизнеса, будет очень сложно получить помощь. Можете ли вы последовательно упростить запрос, подтверждая, что проблема все еще существует? Попытайтесь изолировать проблему - это может быть ошибкой в коде, о котором вы ранее не знали. – mathguy
@mathguy Спасибо за подтверждение о зависимых факторизованных подзапросах. Я думал, что сначала схожу с ума. Я чувствую себя более уверенно в том, что обнаружил некоторую ошибку в Oracle с тем, как я структурировал этот запрос, поэтому я собираюсь начать рефакторинг, чтобы проверить, не могу ли я его изолировать. – DanK