Ситуация
У меня возникли проблемы с планом выполнения запроса среднего размера для большого объема данных в Oracle 11.2.0.2.0. Чтобы ускорить процесс, я ввел фильтр диапазона, который работает примерно так:
PROCEDURE DO_STUFF(
org_from VARCHAR2 := NULL,
org_to VARCHAR2 := NULL)
-- [...]
JOIN organisations org
ON (cust.org_id = org.id
AND ((org_from IS NULL) OR (org_from <= org.no))
AND ((org_to IS NULL) OR (org_to >= org.no)))
-- [...]
Как видите, я хочу ограничить JOIN
из organisations
, используя необязательный диапазон номеров организаций. Клиентский код может вызывать DO_STUFF
с ограничением (предположительно быстрым) или без него (очень медленным).
Проблема
Проблема в том, что PL/SQL создаст переменные связывания для вышеуказанных параметров org_from
и org_to
, чего я и ожидал в большинстве случаев:
-- [...]
JOIN organisations org
ON (cust.org_id = org.id
AND ((:B1 IS NULL) OR (:B1 <= org.no))
AND ((:B2 IS NULL) OR (:B2 >= org.no)))
-- [...]
Обходной путь
Только в этом случае я измерил, что план выполнения запроса будет намного лучше, когда я просто встраиваю значения, т.е. когда запрос, выполняемый Oracle, на самом деле выглядит примерно так:
-- [...]
JOIN organisations org
ON (cust.org_id = org.id
AND ((10 IS NULL) OR (10 <= org.no))
AND ((20 IS NULL) OR (20 >= org.no)))
-- [...]
Под «намного» я имею в виду в 5-10 раз быстрее. Обратите внимание, что запрос выполняется очень редко, т.е. раз в месяц. Поэтому мне не нужно кэшировать план выполнения.
Мои вопросы
Как я могу встроить значения в PL/SQL? Я знаю о EXECUTE IMMEDIATE, но предпочел бы PL/SQL компилирует мой запрос, а не выполняет конкатенацию строк.
Я просто измерил что-то, что произошло случайно, или я могу предположить, что встраивание переменных действительно лучше (в данном случае)? Причина, по которой я спрашиваю, заключается в том, что я считаю, что связанные переменные заставляют Oracle разрабатывать общий план выполнения, тогда как встроенные значения позволяют анализировать очень специфическую статистику столбцов и индексов. Так что могу предположить, что это не просто совпадение.
Я что-то пропустил? Может быть, есть совершенно другой способ добиться улучшения плана выполнения запроса, кроме встраивания переменных (обратите внимание, я также пробовал немало подсказок, но я не эксперт в этой области)?
NO
вORGANIZATIONS
является уникальным ключом? Точна ли статистика в столбцеNO
? - person Justin Cave   schedule 18.03.2011NO
уникален, статистика точная. - person Lukas Eder   schedule 18.03.2011organisations
. У этого всего около 550 записей. Каждая организация имеет более 100 тыс. записей в различных других таблицах, которые связаны с полным запросом. - person Lukas Eder   schedule 18.03.2011EXECUTE IMMEDIATE
. Я изменил порядок вопросов... - person Lukas Eder   schedule 18.03.2011BETWEEN
для фильтра диапазона? Может ли это помочь? - person FrustratedWithFormsDesigner   schedule 18.03.2011BETWEEN
приводит к почти такому же плану выполнения. Вероятно, какой-то очень неортодоксальный индекс мог решить проблему за пределами моего понимания. Но это не объясняет, почему встроенные значения работают намного лучше, чем связанные переменные. Я думаю, мне придется опубликовать запрос... :-) - person Lukas Eder   schedule 18.03.2011org.no
— это столбецVARCHAR2
, но он содержит только 5-значные числа. Итак, я думаю, в моем встроенном примере Oracle выполняет автоматическое приведение типов илиto_char
или что-то в этом роде. Я проверю, имеет ли это какое-то значение для планов выполнения (хотя я был бы удивлен) - person Lukas Eder   schedule 19.03.2011