Вопрос

Ситуация

У меня возникли проблемы с планом выполнения моего запроса для запроса среднего размера по большому объему данных в Oracle 11.2.0.2.0. Чтобы ускорить процесс, я ввел фильтр диапазона, который делает примерно следующее:

родовое слово

Как видите, я хочу ограничить генерирующий кодовый код для JOIN, используя необязательный диапазон номеров организаций. Клиентский код может вызывать organisations с (предположительно быстрым) или без (очень медленным) ограничением.

Проблема

Проблема в том, что PL / SQL создает переменные связывания для указанных выше параметров DO_STUFF и org_from, чего я и ожидал в большинстве случаев:

родовое слово

Обходной путь

Только в этом случае я измерил, что план выполнения запроса будет намного лучше, когда я просто встраиваю значения, т.е. когда запрос, выполняемый Oracle, на самом деле выглядит примерно так

родовое слово

Под "много" я подразумеваю в 5–10 раз быстрее. Обратите внимание, что запрос выполняется очень редко, т.е. раз в месяц. Так что мне не нужно кэшировать план выполнения.

Мои вопросы

  • Как я могу встроить значения в PL / SQL? Я знаю о EXECUTE IMMEDIATE , но я бы предпочел PL / SQL компилирует мой запрос и не выполняет конкатенацию строк.

  • Я просто измерил то, что произошло случайно, или могу предположить, что встраивание переменных действительно лучше (в данном случае)? Причина, по которой я спрашиваю, заключается в том, что я думаю, что переменные связывания вынуждают Oracle разработать общий план выполнения, тогда как встроенные значения позволят анализировать очень специфичную статистику столбцов и индексов . Так что я могу представить, что это не просто совпадение.

  • Я что-то упустил? Может быть, есть совершенно другой способ улучшить план выполнения запроса, кроме встраивания переменных (обратите внимание, я тоже пробовал немало подсказок, но я не эксперт в этой области)?

Это было полезно?

Решение

В одном из своих комментариев вы сказали:

<цитата>

«Также я проверил различные значения привязки. С переменными связывания я получаю ПОЛНЫЙ СКАНИРОВАНИЕ ТАБЛИЦ, в то время как ценностей, план выглядит намного лучше ".

Есть два пути. Если вы передадите NULL для параметров, вы выберете все записи. В этих условиях полное сканирование таблицы - наиболее эффективный способ получения данных. Если вы передаете значения, то индексированные чтения могут быть более эффективными, потому что вы выбираете только небольшое подмножество информации.

Когда вы формулируете запрос с использованием переменных связывания, оптимизатор должен принять решение: должен ли он предполагать, что большую часть времени вы будете передавать значения или что вы будете передавать нули? Трудно. Так что посмотрим на это с другой стороны: что менее эффективно - выполнять полное сканирование таблицы, когда вам нужно только выбрать подмножество записей, или выполнять индексированные чтения, когда вам нужно выбрать все записи?

Похоже, что оптимизатор решил использовать полное сканирование таблицы как наименее неэффективную операцию для всех возможных ситуаций.

В то время как при жестком кодировании значений оптимизатор сразу узнает, что 10 IS NULL оценивается как ЛОЖЬ, и поэтому он может взвесить достоинства использования индексированного чтения для поиска нужных записей подмножества.


Итак, что делать? Как вы говорите, этот запрос выполняется только один раз в месяц, и я думаю, что потребуется лишь небольшое изменение бизнес-процессов, чтобы иметь отдельные запросы: один для всех организаций и один для подгруппы организаций.


<цитата>

"Кстати, удаление предложения: R1 IS NULL не меняет план выполнения много, что оставляет меня с другим сторона условия ИЛИ: R1 <= org.no, где NULL не имеет смысла в любом случае, поскольку org.no НЕ НУЛЕВО "

Итак, дело в том, что у вас есть пара переменных связывания, которые определяют диапазон . В зависимости от распределения значений разные диапазоны могут соответствовать разным планам выполнения. То есть этот диапазон (вероятно) подойдет для сканирования индексированного диапазона ...

родовое слово

... тогда как это, вероятно, больше подходит для полного сканирования таблицы ...

родовое слово

Вот где в игру вступает функция поиска привязанных переменных.

(в зависимости от распределения значений, конечно).

Другие советы

Поскольку планы запросов на самом деле постоянно различаются, это означает, что оценки мощности оптимизатора по какой-то причине отключены. Можете ли вы подтвердить из планов запросов, что оптимизатор ожидает, что условия будут недостаточно избирательными при использовании переменных связывания? Поскольку вы используете 11.2, Oracle следует использовать адаптивное совместное использование курсора , поэтому это не должно быть проблемой поиска переменных привязки (при условии, что в ходе тестирования вы вызываете версию с переменными привязки много раз с разными значениями NO.

Верны ли оценки количества элементов в хорошем плане? Я знаю, что вы сказали, что статистика в столбце NO точна, но я бы с подозрением отнесся к случайной гистограмме, которая может не обновляться, например, в ходе вашего обычного процесса сбора статистики.

Вы всегда можете использовать подсказку в запросе, чтобы принудительно использовать конкретный индекс (хотя с помощью сохранение структуры или стабильности плана оптимизатора было бы предпочтительнее с точки зрения долгосрочного обслуживания). Любой из этих вариантов предпочтительнее динамического SQL.

Однако можно попробовать еще один дополнительный тест - заменить синтаксис соединения SQL 99 старым синтаксисом Oracle, т. е.

родовое слово

Очевидно, это ничего не должно изменить, но с синтаксисом SQL 99 были проблемы с синтаксическим анализатором, поэтому это нужно проверить.

Пахнет Bind Peeking , но я использую только Oracle 10, поэтому я не могу утверждать, что такая же проблема существует в 11.

Это очень похоже на потребность в адаптивном совместном использовании курсора в сочетании со стабильностью SQLPlan. Я думаю, что происходит то, что capture_sql_plan_baselines parameter is true. То же самое и для кодового кода. Если это правда, происходит следующее:

  1. При первом запуске запроса он анализируется и получает новый план.
  2. Во второй раз этот план сохраняется в sql_plan_baselines как принятый план.
  3. Все последующие запуски этого запроса используют этот план, независимо от переменных связывания.

Если Adaptive Cursor Sharing уже активен, оптимизатор сгенерирует новый / лучший план, сохранит его в sql_plan_baselines, но не сможет его использовать, пока кто-то не примет этот новый план как приемлемый альтернативный план. Проверьте use_sql_plan_baselines и посмотрите, есть ли в вашем запросе записи с dba_sql_plan_baselines Вы можете использовать accepted = 'NO' and verified = null для разработки нового плана и его автоматического принятия, если эффективность плана как минимум в 1,5 раза выше, чем без нового плана.

Надеюсь, это поможет.

Я добавил это в качестве комментария, но также предложу здесь.Надеюсь, это не слишком упрощенно, и, глядя на подробные ответы, я могу неправильно понять точную проблему, но в любом случае ...

Кажется, в вашей таблице организаций есть столбец № (org.no), который определяется как номер.В вашем жестко запрограммированном примере вы используете числа для сравнения.

родовое слово

В вашей процедуре вы передаете varchar2 :

родовое слово

Итак, чтобы сравнить varchar2 с числом, Oracle должен будет выполнить преобразования , поэтому это может вызвать полное сканирование.

Решение: изменить процедуру для передачи чисел

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top