Оптимизатор Oracle намекает на функцию xmlagg
У меня есть функция, которая вызывает несколько таблиц / представлений и т. Д. С несколькими xmlaggs данных.
По какой-то причине я получаю повышение производительности, когда извлекаю дополнительную информацию, даже если эта дополнительная информация не используется для остальной части кода (например, индексация значения ключа, используемого снова).
Я запустил tkprof для быстрых и медленных, и я вижу несколько проблем - во-первых, медленный запрос пропускает при разборе и выполнении, тогда как быстрый не делает.
Моя главная проблема заключается в том, что, глядя вглубь, я вижу высокую стоимость для одного из моих представлений - более быстрый запрос использует 3 индекса в базовых таблицах, тогда как медленный не использует ни одного.
Я попытался вставить подсказку:
SELECT /*+ index(view_alias,table1_index, table2_index, table3_index) */
XMLCONCAT (...
Однако он все еще выполняет полное сканирование таблицы. Я помещаю подсказку оптимизатора в неправильное место или использую неправильный синтаксис для этого?
Редактировать - я проводил более тщательное расследование, и кажется, что это может быть попытка Oracle выполнить хеш-соединение, а не вложенный цикл, однако мой выбор сделан из нескольких таблиц - могу ли я принудительно использовать USE_NL для всех 3? Как я узнаю, какая область pl/sql вызывает это, так как она вызывается несколько раз.
Обновление 28/08 - Добавлена награда. Дайте мне знать, если что-нибудь потребуется.
Обновление 01/09 -
> SELECT XMLCONCAT ( XMLELEMENT ( "1", (SELECT XMLCONCAT( XMLELEMENT
> ( "2", XMLELEMENT ( "3", XMLFOREST ( )), CASE WHEN THEN
> XMLELEMENT ( "3", XMLFOREST ( )) END), /* (SELECT XMLELEMENT (
> "4", XMLAGG (XMLELEMENT ("5"))) FROM TABLE t1, t2 WHERE t1.col1 =
> t2.col2) ,*/ CASE WHEN THEN (SELECT XMLAGG ( XMLELEMENT (
> "5", */(SELECT col1 FROM TABLE t1, t2 WHERE t1.col1 = t2.col2),*/
> XMLFOREST ( ....
Есть два закомментированных выбора, которые, когда ЛИБО, не комментируются, превращают его в более быстрый запрос. t1 и t2 НЕ используются в другом месте запроса вообще.
Обновление 01/09 Вот планы выполнения: быстро http://pastebin.com/pbJMSxrB медленно http://pastebin.com/zt3eUYNd
Это дорогие линии 86, которые я хочу исправить. Это может быть результатом полных сканирований здесь или присоединений дальше.
2 ответа
Причиной неиспользования индексов является теоретическая возможность существования нулей. Нули не индексируются, поэтому, если ваш запрос требует / считает, что могут быть нули, он не может получить доступ к таблице через индексы.
Кроме того, ваша подсказка должна быть на том же уровне, что и ваша таблица для чтения:
select /*+parallel(table_a)*/ ...
from (
select ...
from table_a
...
)
...
не будет работать
но
select ...
from (
select /*+parallel(table_a)*/ ...
from table_a
...
)
...
буду работать.
Небольшое изменение в запросе может потенциально повлиять на совсем другую часть запроса. Здесь изменение повлияло на то, как вид VIP_CODES_VW
объединяется (это делается в двух местах, но второе оказывает большее влияние на производительность): в быстром запросе это делается с использованием NESTED LOOPS
(строка 79), а в медленном - HASH JOIN
(строка 75). Рассказать оптимизатору использовать NESTED LOOPS
Вы можете добавить подсказку /*+ USE_NL(VIP_CODES_VW) */
после SELECT
в котором VIP_CODES_VW
запрашивается.