В начале часть условия в WHERE должен быть разложенным пункт (или «декомпилируемый» - или «reengeenered») в более простую форму без использования decode
функции, которые форма может быть понятно оптимизатором запросов:
AND
decode(:P55_DIRECT,'ALL','Y',trim(upper(NA_ORG_OWNER_EMAIL)))=
decode(:P55_DIRECT,'ALL','Y',trim(upper(:P55_DIRECT)))
в:
AND (
:P55_DIRECT = 'ALL'
OR
trim(upper(:P55_DIRECT)) = trimm(upper(NA_ORG_OWNER_EMAIL))
)
Для поиска строки в таблице на основе значений, хранящихся в индексе, Oracle использует метод доступа с именем Индекс сканирования, увидеть эту ссылку для подробностей:
https://docs.oracle.com/cd/B19306_01/server.102/b14211/optimops.htm#i52300
Одним из наиболее распространенных доступа метод Индекс Диапазон сканирования смотрите здесь:
https://docs.oracle.com/cd/B19306_01/server.102/b14211/optimops.htm#i45075
в документации сказано (в последнем ссылке), что:
оптимизатор использует сканирование диапазона, когда он находит один или более ведущих столбцов индекса, указанного в условиях, таких как следующее:
col1 =: b1
col1 <: б1
col1>: б1
И сочетание предыдущих условий для ведущих столбцов в индексе
col1, как «поиск ASD%», не должен находиться в ведущей позиции , иначе условие col1, подобное «% ASD», не приведет к сканированию диапазона .
Вышесказанным означает, что оптимизатор может использовать индекс для поиска строк только для условий запроса, которые содержат основные операторы Comparision: = < > <= >= LIKE
, которые используются для сравнения простых значений с простыми именами столбцов.
В документации, в которой четко не сказано - и вы должны сделать вывод, что она читает между линиями, - это факт, что когда какая-либо функция используется в состоянии, в форме function(column_name)
или function(expression_involving_column_names)
, тогда сканирование диапазона индекса не может быть использовано.
В этом случае оптимизатор запросов должен оценивать это выражение отдельно для каждой строки таблицы, поэтому должен читать все строки (выполнять полное сканирование таблицы).
Краткий вывод и эмпирическое правило:
функции в ИНЕКЕ может помешать оптимизатору использовать индексирует
Если вы видите какую-то функцию где-нибудь в WHERE , то это признак того, что вы являетесь , работающим красным светом
STOP немедленно и три раза подумайте, как эта функция влияет на оптимизатор запросов и производительность вашего запроса , и попробуйте переписать условие в форму, которую оптимизатор способен понять.
Теперь посмотрят на нашем переписано условии:
AND (
:P55_DIRECT = 'ALL'
OR
trim(upper(:P55_DIRECT)) = trimm(upper(NA_ORG_OWNER_EMAIL))
)
и СТОП - Есть еще две функций trim
и upper
примененных к колонку под названием NA_ORG_OWNER_EMAIL. Нам нужно подумать, как они могут повлиять на оптимизатор запросов.
Я предполагаю, что вы создали простой индекс для одного столбца:
CREATE INDEX somename ON GCR_ITEMS(NA_ORG_OWNER_EMAIL)
.
Если да, то индекс содержит только простые значения NA_ORG_OWNER_EMAIL.
Но запрос пытается найти значения trimm(upper(NA_ORG_OWNER_EMAIL))
, которые не хранятся в индексе, поэтому этот индекс не может быть использован в этом случае.
Это условие требует, основанный индекса функции:
https://docs.oracle.com/cd/E11882_01/appdev.112/e41502/adfns_indexes.htm#ADFNS00505
CREATE INDEX somename ON GCR_ITEMS(trim(upper(NA_ORG_OWNER_EMAIL)))
К сожалению, даже индекс функции на основе все равно не поможет, потому что условие в запросе слишком общее - если значение: P55_DIRECT = ВСЕ запрос должен извлекать все строки из таблицы (выполнить полное сканирование таблицы), в противном случае должен использовать индекс для поиска значения внутри него.
Это потому, что запрос запланирован (подумайте об этом как «скомпилированный») оптимизатором запросов только один раз, во время его первого выполнения. Затем план хранится в кеше и используется для выполнения запроса для всех последующих исполнений. Значение параметра не известно заранее, поэтому в плане должны учитываться все возможные случаи, поэтому всегда будет выполняться полное сканирование таблицы.
В 1 есть новая функция «Адаптивная оптимализация запроса»:
https://docs.oracle.com/database/121/TGSQL/tgsql_optcncpt.htm#TGSQL94982
где оптимизатор запросов анализирует каждый параметры запроса на каждый работает, и в состоянии обнаружить, что план не является оптимальным для некоторых параметров среды выполнения, и выберите лучшие «подпланы» в зависимости от значения фактического параметра ... но вы должны использовать 12c и дополнительно платить за Enterprise Edition, потому что только это издание включает эту функцию. И все же неясно, будет ли адаптивный план работать в этом случае или нет.
Что вы можете сделать, не оплачивая 12c EE, - это ОТДЕЛАТЬ этот общий запрос в два отдельных варианта: один для случая, когда: P55_DIRECT = ALL, а другой для остальных случаев и запускает соответствующий вариант на клиенте (ваш приложение) в зависимости от значения этого параметра.
Версия для: P55_DIRECT = ALL, который будет выполнять полное сканирование таблицы
where gcr_deals.GCR_DEALS_ID=gcr_items.GCR_DEALS_ID
and
gcr_deals.bu_id=:P0_BU_ID
order by 1
и версии для других случаев, которые будет использовать индекс на основе функции:
where gcr_deals.GCR_DEALS_ID=gcr_items.GCR_DEALS_ID
and
gcr_deals.bu_id=:P0_BU_ID
and
trim(upper(:P55_DIRECT)) = trimm(upper(NA_ORG_OWNER_EMAIL))
order by 1
Можете ли вы опубликовать план выполнения и индексы на ваших таблицах? – Aleksej
Не зная, какие индексы присутствуют на ваших столах и не видя плана выполнения, невозможно угадать, что происходит. Измените свой вопрос и укажите: A) DDL для обеих таблиц, B) все индексы на обеих таблицах, C) план выполнения и D) количество строк в каждой таблице. Благодарю. –
'gcr_items' содержит только 7386 строк - я сомневаюсь, что доступ к индексу действительно улучшит производительность, поскольку, по-видимому, вы выбираете все строки из этой таблицы –