SQL существует почему выбор rownum вызывает неэффективный план выполнения?
Я пытаюсь понять, почему то, что кажется незначительным различием в этих двух запросах обновления синтаксиса Oracle, вызывает радикально другой план выполнения.
запрос 1:
UPDATE sales s
SET status = 'DONE', trandate = sysdate
WHERE EXISTS (Select *
FROM tempTable tmp
WHERE s.key1 = tmp.key1
AND s.key2 = tmp.key2
AND s.key3 = tmp.key3)
запрос 2:
UPDATE sales s
SET status = 'DONE', trandate = sysdate
WHERE EXISTS (Select rownum
FROM tempTable tmp
WHERE s.key1 = tmp.key1
AND s.key2 = tmp.key2
AND s.key3 = tmp.key3)
Как вы можете видеть, единственное различие между ними заключается в том, что подзапрос в запросе 2 возвращает rownum вместо значений каждой строки.
планы выполнения для этих двух не может быть более разные:
Query1-извлекает общие результаты из обеих таблиц и использует сортировку и hashjoin для возврата результатов. Это хорошо сочетается с благоприятной стоимостью 2,346 (несмотря на использование предложения EXISTS и Связного подзапроса).
Query2-тянет оба результата таблицы, а также, но использует счетчик и фильтр для выполнения той же задачи и возвращает план выполнения с удивительной стоимостью 77,789,696! Я должен отметить, что его запрос просто висит на мне, поэтому я не уверен, что это возвращает те же результаты (хотя я считаю, что это должно).
из моего понимания предложения Exists это просто простая логическая проверка, которая выполняется в строке главной таблицы. Не имеет значения, возвращается ли одна строка в моем состоянии EXISTS или 100 000 строк... если какие-либо результаты возвращаются для строки, которая выполняется, то вы прошли проверку exist. Так почему это имеет значение, что мой подзапрос SELECT оператор возвращается?
--------------------изменить----------------------
по запросу ниже приведены планы выполнения, которые я запускаю в TOAD... обратите внимание, что я отредактировал имена таблиц в моем примере выше для удобства - в этих планах ALSS_SALES2 = sales выше и SALESEXT_TMP = tempTABLE выше.
также следует упомянуть, но ни одна из двух таблиц не имеет индексов на данный момент.. Я еще не добавил их в свой tempTable, и я тестирую с дешевой копией таблица продаж, которая содержит только поля и данные, но не индексы, ограничения или безопасность.
Спасибо за помощь всем!
Запрос 1 План Выполнения
Запрос 2 План Выполнения
------------------------------------------------
вопросы
1) Почему вызов rownum вызвал план исполнения изменить?
2) Что такого в фильтре, который настолько невероятно неэффективен?
3) я упускаю что-то фундаментальное с тем, как работает предложение Exists, которое вызывает это изменение?
2 ответов
размещение фактических планов запросов было бы весьма полезно.
в общем случае, когда оптимизатор видит подзапрос с rownum
, что радикально ограничивает его способность преобразовывать запрос и объединять результаты из подзапроса с основным запросом, потому что это потенциально влияет на результаты. Это может быть быстрый способ заставить Oracle материализовать подзапрос, если это окажется более эффективным, чем план, выбранный оптимизатором. В этом случае, однако, это вероятно, это заставляет оптимизатор отказаться от шага преобразования, который делает запрос более эффективным.
иногда, вы увидите, что кто-то примет запрос
SELECT b.*
FROM (SELECT <<columns>>
FROM driving_table
WHERE <<conditions>>) a,
b
WHERE a.id = b.id
и вдогонку rownum
до a
подзапрос
SELECT b.*
FROM (SELECT <<columns>>, rownum
FROM driving_table
WHERE <<conditions>>) a,
b
WHERE a.id = b.id
для того, чтобы заставить оптимизатор оценить a
подзапрос перед выполнением соединения. Обычно, конечно, оптимизатор должен делать это по умолчанию, если он более эффективен. Но если оптимизатор ошибается, добавляя rownum
может быть быстрее, чем выяснить правильный набор подсказок, чтобы заставить план или копаться в основной проблеме, чтобы выяснить правильное решение.
конечно, в частном случае, когда у вас есть подзапрос в WHERE EXISTS
где единственное использование rownum
входит в SELECT
список, мы, люди, можем обнаружить, что rownum
не должен препятствовать любому шагу преобразования запроса, который оптимизатор хотел бы использовать. Оптимизатор, однако, вероятно, использует более общее правило, которое гласит: это подзапросы, которые ссылаются на функцию, такую как rownum
должен быть полностью выполнен (это может зависеть от точной версии Oracle и/или настроек оптимизатора). Таким образом, оптимизатор реально делает кучу дополнительной работы, потому что он недостаточно умен, чтобы признать, что rownum
добавленное невозможно повлиять на результаты запроса.
просто вопрос, каков план выполнения этого запроса:
UPDATE sales s
SET status = 'DONE', trandate = sysdate
WHERE EXISTS (Select NULL
FROM tempTable tmp
WHERE s.key1 = tmp.key1
AND s.key2 = tmp.key2
AND s.key3 = tmp.key3);
он визуализирует то, что необходимо в EXISTS (...)
выражение - на самом деле ничего! Как уже говорилось, Oracle просто нужно проверить если все возвращается, а не что возвращается в подзапросе.