Oracle EXECUTE НЕМЕДЛЕННЫЕ изменения объясняют план запроса - PullRequest
3 голосов
/ 07 мая 2010

У меня есть хранимая процедура, которую я вызываю, используя EXECUTE IMMEDIATE. Проблема, с которой я сталкиваюсь, заключается в том, что план объяснения отличается, когда я вызываю процедуру напрямую, и когда я использую EXECUTE IMMEDIATE для вызова процедуры. Это приводит к увеличению времени выполнения в 5 раз. Основное различие между планами заключается в том, что когда я использую команду «выполнить немедленно», оптимизатор не удаляет подзапрос (я использую условие «НЕ СУЩЕСТВУЕТ»). Мы используем Оптимизатор на основе правил здесь для большинства запросов, но в этом есть подсказка для использования индекса, поэтому используется CBO (однако мы не собираем статистику по таблицам). Мы работаем с Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64-битная версия.

Пример: Быстро:

begin
   package.procedure;
end;
/

Slow:

begin
   execute immediate 'begin package.' || proc_name || '; end;';
end;
/

Запрос:

  SELECT                                               /*+ INDEX(A IDX_A_1) */
        a.store_cd,
           b.itm_cd itm_cd,
           CEIL ( (new_date - a.dt) / 7) week_num,
           SUM (a.qty * b.demand_weighting * b.CONVERT) qty
    FROM            a
                 INNER JOIN
                    b
                 ON (a.itm_cd = b.old_itm_cd)
              INNER JOIN
                 (SELECT   g.store_grp_cd, g.store_cd
                    FROM   g, h
                   WHERE   g.store_grp_cd = h.fdo_cd AND h.fdo_type = '1') d
              ON (a.store_cd = d.store_cd AND b.store_grp_cd = d.store_grp_cd)
           CROSS JOIN
              dow
   WHERE       a.dt BETWEEN dow.new_date - 91 AND dow.new_date - 1
           AND a.sls_wr_cd = 'W'
           AND b.demand_type = 'S'
           AND b.old_itm_cd IS NOT NULL
           AND NOT EXISTS
                 (SELECT
                        NULL
                    FROM   f
                   WHERE   f.store_grp_cd = a.store_cd
                           AND b.old_itm_cd = f.old_itm_cd)
GROUP BY   a.store_cd, b.itm_cd, CEIL ( (dow.new_date - a.dt) / 7)

Хороший план объяснения:

OPERATION       OPTIONS         OBJECT_NAME     OBJECT_TYPE     ID      PARENT_ID
SELECT STATEMENT                                                0       
SORT            GROUP BY                                        1       0
NESTED LOOPS                                                    2       1
HASH JOIN       ANTI                                            3       2
TABLE ACCESS    BY INDEX ROWID  H                               4       3
NESTED LOOPS                                                    5       4
NESTED LOOPS                                                    6       5
NESTED LOOPS                                                    7       6
TABLE ACCESS    FULL            B                               8       7
TABLE ACCESS    BY INDEX ROWID  A                               9       7
INDEX           RANGE SCAN      IDX_A_1         UNIQUE          10      9
INDEX           UNIQUE SCAN     G               UNIQUE          11      6
INDEX           RANGE SCAN      H_UK            UNIQUE          12      5
TABLE ACCESS    FULL            F                               13      3
TABLE ACCESS    FULL            DOW                             14      2

План плохого объяснения:

OPERATION       OPTIONS         OBJECT_NAME     OBJECT_TYPE     ID      PARENT_ID
SELECT STATEMENT                                                0       
SORT            GROUP BY                                        1       0
NESTED LOOPS                                                    2       1
NESTED LOOPS                                                    3       2
NESTED LOOPS                                                    4       3
NESTED LOOPS                                                    5       4
TABLE ACCESS    FULL            B                               6       5
TABLE ACCESS    BY INDEX ROWID  A                               7       5
INDEX           RANGE SCAN      IDX_A_1         UNIQUE          8       7
TABLE ACCESS    FULL            F                               9       8
INDEX           UNIQUE SCAN     G               UNIQUE          10      4
TABLE ACCESS    BY INDEX ROWID  H                               11      3
INDEX           RANGE SCAN      H_UK            UNIQUE          12      11
TABLE ACCESS    FULL            DOW                             13      2

В плане плохого объяснения подзапрос не является необоснованным. Я смог воспроизвести плохой план, добавив подсказку no_unnest в подзапрос; тем не менее, я не смог воспроизвести хороший план, используя нестандартный совет (при запуске процедуры с использованием команды «немедленное выполнение»). Другие подсказки учитываются оптимизатором при использовании немедленного выполнения, а не нежелательной подсказки.

Эта проблема возникает только тогда, когда я использую execute немедленно для вызова процедуры. Если я использую команду execute немедленно для самого запроса, он использует хороший план.

Ответы [ 4 ]

1 голос
/ 09 декабря 2010

Оказывается, это известная ошибка в Oracle 9i. Ниже приведен текст сообщения об ошибке.

Немедленное выполнение плана неверного запроса [ID 398605.1]

Изменено 09-НОЯБРЯ-2006 Тип ПРОБЛЕМА Статус ИЗМЕНЕНО

Этот документ доставляется вам через процесс быстрой видимости (RaV) службы поддержки Oracle и поэтому не подлежал независимой технической проверке.

Относится к: Oracle Server - Enterprise Edition - Версия: 9.2.0.6 Эта проблема может возникать на любой платформе.

Симптомы Когда процедура запускается через «выполнить немедленно», созданный план отличается от того, когда процедура запускается напрямую.

Причина Причина этой проблемы была выявлена ​​и проверена в неопубликованной ошибке 2906307. Это вызвано тем фактом, что операторы SQL, выданные из PLSQL на рекурсивной глубине, превышающей 1, могут получить планы выполнения, отличные от планов выполнения, выпущенных непосредственно из SQL. , Эта ошибка затрагивает несколько функций оптимизатора (например, _unnest_subquery, _pred_move_around = true). СОВЕТЫ, связанные с функциями, также можно игнорировать.

Эта ошибка охватывает ту же базовую проблему, что и ошибка 2871645 Объединение сложных представлений происходит не для рекурсивного SQL> глубина 1, а для функций, отличных от объединения сложных представлений.

Ошибка 2906307 закрывается как дубликат ошибки 3182582 ЗАЯВЛЕНИЕ SQL ЗАПУСКАЕТСЯ МЕДЛЕННО В DBMS_JOB, ЧЕМ В SQL * PLUS. Исправлено в 10.2

Решение Для операторов вставки используйте подсказку BYPASS_RECURSIVE_CHECK: INSERT / * + BYPASS_RECURSIVE_CHECK * / INTO таблица

Ссылки BUG: 2871645 - СЛОЖНОЕ ОБЪЕДИНЕНИЕ ПРОСМОТРА НЕ ПРОИСХОДИТ ДЛЯ РЕКУРСИВНОГО SQL> ГЛУБИНА 1 Ошибка: 3182582 - ЗАПУСК SQL ЗАЯВЛЕНИЯ В СУБД DBMS_JOB, ЧЕМ В SQL * PLUS

1 голос
/ 10 мая 2010

Есть несколько шагов, которые вы можете сделать.первая - трассировка 10046.

В идеале я бы запустил трассировку для одного сеанса, который выполняет как «хорошие», так и «плохие» запросы.Файл трассировки должен содержать оба запроса с жестким разбором.Я был бы заинтересован, ПОЧЕМУ второй имеет жесткий анализ, так как, если у него та же структура SQL и тот же пользователь синтаксического анализа, для второго жесткого анализа не так много причин.Один и тот же сеанс должен означать, что нет никаких странностей из-за разных настроек памяти и т. Д.

SQL не показывает никакого использования переменных, поэтому не должно быть проблем с типом данных.Все столбцы «привязаны» к псевдониму таблицы, поэтому нет смысла путать переменные со столбцами.

Более экстремальный шаг - трассировка 10053.На сайте Джонатана Льюиса есть зритель .Это может позволить вам разобраться в причинах оптимизации, чтобы попытаться выяснить причину различий в планах.

В более широком смысле 9i в значительной степени мертва, а RBO в значительной степени мертва.Я бы серьезно оценил проект по переносу приложения в CBO.Существуют функции, которые вынуждают использовать CBO, и без статистики эта проблема будет появляться.

1 голос
/ 14 мая 2010

Оказывается, это известная ошибка в Oracle 9i. Ниже приведен текст сообщения об ошибке.

Немедленное выполнение дает неверный план запроса [ID 398605.1]

Modified 09-NOV-2006     Type PROBLEM     Status MODERATED

Этот документ доставляется вам через процесс быстрой видимости (RaV) службы поддержки Oracle и поэтому не подлежал независимой технической проверке.

Относится к: Oracle Server - Enterprise Edition - Версия: 9.2.0.6 Эта проблема может возникнуть на любой платформе.

Симптомы Когда процедура запускается через «выполнить немедленно», созданный план отличается от того, когда процедура запускается напрямую.

Причина Причина этой проблемы была выявлена ​​и подтверждена в неопубликованной ошибке 2906307. Это вызвано тем, что операторы SQL, выданные из PLSQL на рекурсивном Глубина больше 1 может получить планы выполнения, отличные от планов, выданных непосредственно из SQL. Эта ошибка затрагивает несколько функций оптимизатора (например, _unnest_subquery, _pred_move_around = true) СОВЕТЫ, связанные с функциями, также могут быть проигнорированы.

Эта ошибка охватывает ту же основную проблему, что и ошибка 2871645 Слияние сложных представлений не происходит для рекурсивный SQL> глубина 1, но для функций, отличных от объединения сложных представлений.

Ошибка 2906307 закрыта как дубликат ошибки 3182582 ЗАЯВЛЕНИЕ SQL ЗАПУСКАЕТСЯ МЕДЛЕННО В DBMS_JOB, ЧЕМ В SQL * PLUS Фиксировано в 10.2

Решение Для операторов вставки используйте подсказку BYPASS_RECURSIVE_CHECK: INSERT / * + BYPASS_RECURSIVE_CHECK * / INTO таблица

Ссылки Ошибка: 2871645 - Слияние сложных представлений не происходит для рекурсивного SQL> DEPTH 1 ОШИБКА: 3182582 - ЗАЯВЛЕНИЕ SQL ЗАПУСКАЕТСЯ МЕНЬШЕ В СУБД, чем в SQL * ПЛЮС

1 голос
/ 08 мая 2010

Вы использовали синтаксис соединения ANSI, который заставит использовать CBO (см. http://jonathanlewis.wordpress.com/2008/03/20/ansi-sql/)

«После того, как вы начнете работать на основе затрат без статистики, появятся всевозможные мелочи, которых может быть достаточно, чтобы вызвать неожиданное поведение в плане выполнения».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...