Arhn - архитектура программирования

Oracle EXECUTE IMMEDIATE изменяет план запроса

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

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

begin
   package.procedure;
end;
/

Медленный:

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; однако мне не удалось воспроизвести хороший план с помощью подсказки unnest (при запуске процедуры с немедленным выполнением). Другие подсказки учитываются оптимизатором при использовании немедленного выполнения, а не подсказки unnest.

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


  • Я думаю, что опримайзер, основанный на правилах, должен быть последовательным. может быть, добавить подсказку и посмотреть, изменит ли это план - чтобы убедиться, что RBO действительно действует ... 07.05.2010
  • У нас есть подсказка для использования индекса в запросе, значит ли это, что вместо этого для запроса будет использоваться CBO? Тем не менее, я попытался добавить в подзапрос несложный намек, но он, похоже, не соблюдает его. 07.05.2010
  • Подсказка индекса не приведет к использованию CBO. Вы можете использовать подсказки FIRST_ROWS или ALL_ROWS, чтобы принудительно использовать CBO, или подсказку RULE, чтобы принудительно использовать RBO. Возможно, вам стоит опубликовать фактический SQL-запрос и два разных плана, которые вы видите для него. 07.05.2010
  • Пожалуйста, опубликуйте актуальные запросы и сгенерированные планы, и тогда, возможно, мы сможем предложить предложения. Одно: если у вас нет статистики на ваших столах, мой опыт показывает, что CBO почти наверняка даст вам паршивый план. Какая версия Oracle у вас установлена? 07.05.2010
  • Я включил запрос и два плана объяснения в свой пост. 07.05.2010

Ответы:


1

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

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

08.05.2010
  • Я пробовал использовать в этом запросе соединения как ANSI, так и не ANSI. Исходный запрос был не ANSI, но в итоге я вставил ANSI. У меня все еще была та же проблема с обоими стилями. 09.05.2010

  • 2

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

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

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

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

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

    09.05.2010

    3

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

    При немедленном выполнении - плохой план запроса [ID 398605.1]

    Modified 09-NOV-2006     Type PROBLEM     Status MODERATED
    

    Этот документ доставляется вам через процесс Rapid Visibility (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 table

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

    13.05.2010
  • Нечто подобное все еще происходит в 10.2.0.4 04.06.2010

  • 4

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

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

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

    Этот документ доставляется вам через процесс Rapid Visibility (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 table

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

    09.12.2010
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..