Управление зависимостями и перекомпиляция в PL/SQL

Стас Белков

Стас Белков

Автор статьи. Известный специалист в мире IT. Консультант по продуктам и решениям Oracle. Практикующий программист и администратор баз данных. Подробнее.

Зависимости и перекомпиляция кода в PL/SQLЕще одной важной фазой компиляции и выполнения PL/SQL-программы является проверка ее зависимостей. Зависимость в PL/SQL представляет собой вид связи между программой и некоторым объектом Oracle, существующим вне этой программы. Серверные программы PL/SQL могут зависеть от таблиц, представлений, типов данных, процедур, функций, последовательностей и спецификаций пакетов, но не от тела пакетов или типов данных (последние относятся к «скрытой» реализации).



Основная цель проверки зависимостей в PL/SQLне допустить выполнения программы, если хоть один из объектов, от которых она зависит, изменился с момента ее последней компиляции.

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

В Oracle10g и более ранних версиях зависимости отслеживались на уровне программных модулей. Если процедура зависела от функции пакета или столбца таблицы, то зависимой единицей становился пакет или таблица. Такой уровень детализации считался стандартным с первых дней PL/SQL и до недавнего времени.

В Oracle11g детализация отслеживания зависимостей была улучшена. Зависимости теперь отслеживаются не до уровня пакетов или таблиц, а до отдельных элементов (например, столбцов таблицы или программ пакета вместе с формальными параметрами вызова и режимами передачи). Точное отслеживание зависимостей означает, что программа останется действительной в случае добавления или перегрузки существующей программы в существующем пакете. Аналогичным образом при добавлении нового столбца в таблицу база данных не объявит недействительными все программы PL/ SQL, ссылающиеся на эту таблицу, — только те программы, которые ссылаются на все столбцы (например, с использованием конструкции SELECT * или объявления %ROWTYPE). В следующих разделах эта ситуация рассматривается более подробно.

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

К сожалению, в Oracle11g Release 2 эти данные все еще недоступны в представлениях словарей данных. Хочется верить, что в будущем информация станет доступной.

А пока использование любых версий, предшествующих Oracle11g, означает, что при любых изменениях в базах данных многие объекты будут автоматически становиться недействительными.

 

 

Анализ зависимостей с использованием представлений словаря данных

Для анализа зависимостей можно использовать некоторые представления словаря данных. Рассмотрим простой пример. Допустим, на сервере имеется пакет bookworm, а в нем имеется функция, извлекающая данные из таблицы books. Непосредственно после создания и таблица, и пакет действительны (valid):

SELECT object_name, object_type, status 
      FROM USER_OBJECTS 
   WHERE object_name = 'BOOKWORM';

OBJECT_NAME                    OBJECT_TYPE        STATUS
------------------------------ ------------------ -------
BOOKWORM                       PACKAGE            VALID
BOOKWORM                       PACKAGE BODY       VALID

При компиляции программы PL/SQL база данных формирует список объектов, необходимых для успешной компиляции пакета BOOKWORM. Для определения всех зависимостей между объектами можно построить граф зависимостей при помощи запроса к представлению USER_DEPENDENCIES:

SELECT name, type, referenced_name, referenced_type
      FROM USER_DEPENDENCIES
   WHERE name = 'BOOKWORM';

NAME            TYPE           REFERENCED_NAME REFERENCED_TYPE
--------------- -------------- --------------- ---------------
BOOKWORM        PACKAGE        STANDARD        PACKAGE
BOOKWORM        PACKAGE BODY   STANDARD        PACKAGE
BOOKWORM        PACKAGE BODY   BOOKS           TABLE
BOOKWORM        PACKAGE BODY   BOOKWORM        PACKAGE

На рис. 1 эта информация представлена в виде ориентированного графа, на котором стрелки обозначают отношения типа «зависит от». Иначе говоря, на рис. 1 показано, что спецификация и тело пакета bookworm зависят от встроенного пакета STANDARD (см. врезку «Пакет STANDARD»), а тело пакета bookworm — от его же спецификации и от таблицы books.

 

Граф зависимостей пакета bookworm

 

Рис. 1. Граф зависимостей пакета bookworm

 

Для отслеживания зависимостей Oracle записывает в словарь данных тело и спецификацию пакета как два разных элемента. Тело любого пакета зависит от его спецификации, но спецификация никогда не зависит от тела. От тела пакета не зависит ни один объект — собственно говоря, тела может и вовсе не быть.

Если вам приходилось достаточно долго заниматься сопровождением программного кода, вы знаете, что при подобном анализе учитываются не столько зависимости, сколько ссылки одних объектов на другие. Предположим, мне нужно изменить структуру таблицы books. Прежде всего необходимо выяснить, на какие из объектов это может повлиять:

SELECT name, type
      FROM USER_DEPENDENCIES
   WHERE referenced_name = 'BOOKS'
      AND referenced_type = 'TABLE';

NAME                           TYPE
------------------------------ ------------
ADD_BOOK                       PROCEDURE
TEST_BOOK                      PACKAGE BODY
BOOK                           PACKAGE BODY
BOOKWORM                       PACKAGE BODY
FORMSTEST                      PACKAGE

Как видите, кроме пакета bookworm в схеме присутствуют и другие программы, ранее не упоминавшиеся. Но Oracle ничего не забывает!

И хотя Oracle очень тщательно отслеживает все зависимости, все предусмотреть невозможно: в словаре данных отслеживаются только зависимости локальных хранимых объектов, ссылки на которые оформлены в виде статических вызовов. Существует множество способов создания программ, которые не будут отражены в представлении USER_DEPENDENCIES. К их числу относятся внешние программы с интегрированным кодом SQL или PL/SQL, удаленные хранимые процедуры, клиентские программы с вызовами локальных хранимых объектов и любые локальные программы, в которых используется динамический SQL.

Попробуем изменить структуру таблицы books, добавив в нее один новый столбец:

ALTER TABLE books MODIFY popularity_index NUMBER (8,2);

Oracle сразу же автоматически пометит все ссылки на таблицу books как недействительные (или в Oracle11g — только программные модули, в которых используется этот столбец). При любом изменении определения объекта, даже при его перекомпиляции без внесения изменений, все ссылки на объект также будут помечены как недействительные. Но на практике этот процесс еще сложнее. Если вы являетесь владельцем программы, выполняющей заданную команду DML со ссылкой на таблицу другой схемы, то после лишения вас привилегий на выполнение указанной команды вся программа помечается как недействительная.

Запрос к представлению USER_OBJECTS выводит следующую информацию :

/* Файл в Сети: invalid_objects.sql */
   SELECT object_name, object_type, status
      FROM USER_OBJECTS
   WHERE status = 'INVALID';

OBJECT_NAME                    OBJECT_TYPE        STATUS
------------------------------ ------------------ -------
ADD_BOOK                       PROCEDURE          INVALID
BOOK                           PACKAGE BODY       INVALID
BOOKWORM                       PACKAGE BODY       INVALID
FORMSTEST                      PACKAGE            INVALID
FORMSTEST                      PACKAGE BODY       INVALID
TEST_BOOK                      PACKAGE BODY       INVALID

Кстати, этот пример в очередной раз демонстрирует преимущества разбиения пакетов на две части: в большинстве случаев пометкой INVALID снабжаются тела пакетов, а не их спецификации. Если спецификация не изменяется, то и программные модули, зависящие от пакета, не будут объявлены недействительными. В данном примере недействительной объявлена только спецификация FORMSTEST, зависящая от таблицы books, потому что в ней используется объявление books%ROWTYPE.

И последнее замечание: для анализа программных зависимостей также можно воспользоваться процедурой Oracle DEPTREE_FILL в сочетании с представлениями DEPTREE или IDEPTREE.

Например, если запустить процедуру командой:

BEGIN DEPTREE_FILL('TABLE', USER, 'BOOKS'); END;

я смогу получить удобную информацию, запросив данные из представления IDEPTREE:

SQL> SELECT * FROM IDEPTREE;

DEPENDENCIES
-------------------------------------------
TABLE SCOTT.BOOKS
   PROCEDUE SCOTT.ADD_BOOK
   PACKAGE BODY SCOTT.BOOK
   PACKAGE BODY SCOTT.TEST_BOOK
   PACKAGE BODY SCOTT.BOOKWORM
   PACKAGE SCOTT.FORMSTEST
      PACKAGE BODY SCOTT.FORMSTEST

В листинге приведен результат рекурсивного запроса. Если вы захотите использовать эти объекты, выполните сценарий $ORACLE_HOME/rdbms/admin/utldtree.sql для построения вспомогательной процедуры и представлений в вашей схеме. Или при желании смоделируйте его запросом вида:

SELECT RPAD (' ', 3*(LEVEL-1)) || name || ' (' || type || ') '
   FROM user_dependencies
      CONNECT BY PRIOR RTRIM(name || type) =
            RTRIM(referenced_name || referenced_type)
         START WITH referenced_name = 'имя' AND referenced_type = 'тип'

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

 

ПАКЕТ STANDARD

 

 

Детализация зависимостей (Oracle 11g)

Одной из самых замечательных возможностей PL/SQL является автоматизированный контроль зависимостей. Oracle автоматически отслеживает все объекты базы данных, от которых зависит программный модуль. Если какие-либо из этих объектов будут изменены, программный модуль помечается как недействительный, а его использование становится возможным только после перекомпиляции. Так, в примере с пакетом scope_demo при включении запроса из таблицы employees пакет помечается как зависимый от этой таблицы.

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

Возьмем пакет scope_demo: он зависит от таблицы employees, но в нем используются только столбцы department_id и salary. В Oracle10g в случае изменения размера столбца first_name пакет помечался как недействительный.

В Oracle11g система отслеживания зависимостей была детализирована до отдельных элементов внутри объектов. Для таблиц Oracle теперь отслеживает зависимости программного модуля от конкретных столбцов. Подобная детализация предотвращает лишние перекомпиляции и упрощает развитие кодовой базы приложения.

В Oracle Database 11g и выше я могу изменить размер столбца first_name, и этот столбец не будет помечен как недействительный:

ALTER TABLE employees MODIFY first_name VARCHAR2(2000)
/
Table altered.
SELECT object_name, object_type, status 
      FROM all_objects
   WHERE owner = USER AND object_name = 'SCOPE_DEMO'/

OBJECT_NAME                    OBJECT_TYPE         STATUS
------------------------------ ------------------- -------
SCOPE_DEMO                     PACKAGE             VALID
SCOPE_DEMO                     PACKAGE BODY        VALID

Однако следует заметить, что без полного уточнения всех ссылок в переменных PL/ SQL во встроенных командах SQL вы не сможете в полной мере пользоваться этим усовершенствованием.

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

Возьмем исходную, неуточненную команду SELECT в set_global:

SELECT COUNT (*)
      INTO l_count 
      FROM employees
   WHERE department_id = l_inner AND salary > l_salary;

В Oracle Database 11g вследствие детализации зависимостей база данных «заметит», что пакет scope_demo зависит только от department_id и salary.

Теперь предположим, что администратор базы данных добавит столбец в таблицу employees. Так как в команде SELECT присутствуют неуточненные ссылки на переменные PL/SQL, может оказаться, что имя нового столбца изменит информацию зависимостей для этого пакета. А именно, если имя нового столбца совпадает с неуточненной ссылкой в переменной PL/SQL, база данных разрешит ссылку на имя столбца. По этой причине база данных должна обновить информацию зависимостей для scope_demo, а это означает, что пакет должен быть объявлен недействительным.

И наоборот, если уточнять ссылки на все переменные PL/SQL во встроенных командах SQL, при компиляции программного модуля база данных будет знать об отсутствии возможных неоднозначностей. Даже при добавлении столбцов программа будет оставаться действительной (valid).

Следует учесть, что список INTO запроса не является частью команды SQL. В результате переменные из списка не сохраняются в команде SQL, генерируемой компилятором PL/SQL. Соответственно, уточнение переменной именем области действия (или его отсутствие) не повлияет на анализ зависимостей базы данных.

 

 

Удаленные зависимости в PL/SQL

Серверный код PL/SQL становится недействительным при любом изменении кода локального объекта, от которого он зависит. Однако если такой объект находится на другом компьютере, локальная копия Oracle не пытается объявить вызывающую программу PL/SQL недействительной в реальном времени. Вместо этого проверка откладывается до момента вызова.

Следующая программа зависит от процедуры recompute_prices, которая находится по ссылке findat.ldn.world:

PROCEDURE synch_em_up (tax_site_in IN VARCHAR2, since_in IN DATE)
IS
BEGIN
   IF tax_site_in = 'LONDON'
   THEN
      recompute_prices(Sfindat.ldn.world(cutoff_time => since_in);
   END IF;
END;

Если удаленная процедура будет перекомпилирована, то при последующих попытках выполнить synch_em_up, скорее всего, будет получено сообщение об ошибке ORA-04062, уведомляющее об изменении временной метки (или сигнатуры) пакета SCOTT.recompute_ prices. Если вызов остается действительным, Oracle перекомпилирует synch_em_up, и в случае успешного завершения следующий вызов будет выполнен успешно. Чтобы понять, как работает механизм вызова удаленных процедур, нужно знать, что компилятор PL/ SQL хранит для каждой удаленной процедуры временную метку и сигнатуру.

  •  Временная метка — дата и время (с точностью до секунды) последнего изменения спецификации объекта, взятые из столбца TIMESTAMP представления USER_OBJECTS. В программах PL/SQL это не обязательно то же самое, что время последней компиляции, поскольку возможна перекомпиляция объекта без изменения его спецификации. (Указанный столбец имеет тип данных DATE, а не более новый тип TIMESTAMP.)
  •  Сигнатура — упрощенная спецификация объекта. Сигнатура определяет имя объекта, а также типы данных, порядок и режимы использования его параметров. Таким образом, при компиляции процедуры synch_em_up Oracle извлекает временную метку и сигнатуру удаленной процедуры recomputed_prices и сохраняет их в байт-коде процедуры synch_em_up.

Дальше все просто: во время выполнения программы в зависимости от текущего значения параметра REMOTE_DEPENDENClES_MODE Oracle сравнивает либо временную метку, либо сигнатуру удаленной процедуры со значением в байт-коде локальной процедуры, и если они не совпадают, выдает ошибку ORA-04062.

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

ALTER SESSION SET REMOTE_DEPENDENCIES_MODE = SIGNATURE;

либо в коде PL/SQL:

EXECUTE IMMEDIATE 'ALTER SESSION SET REMOTE_DEPENDENCIES_MODE = SIGNATURE';

После этого до конца сеанса во всех программах PL/SQL будет использоваться метод проверки сигнатуры. Клиентские средства Oracle всегда выполняют команду ALTER SESSION...SIGNATURE сразу после подключения к базе данных, переопределяя настройки в инициализационном файле Oracle.

Oracle рекомендует использовать метод проверки сигнатуры в клиентских средствах (например, в Oracle Forms), а метод проверки временной метки — в межсерверных вызовах процедур. Однако учтите, что первый метод может стать причиной возникновения псевдоошибок в приложениях. Если исполняющее ядро ошибочно посчитает, что сигнатура программы не изменилась, Oracle не станет помечать как недействительную ту программу, из которой она вызывается. Тогда могут появиться трудноуловимые ошибки вычислений. Примеры опасных ситуаций такого рода:

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

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

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

На практике сведение к минимуму перекомпиляций может существенно отразиться на доступности приложения. Дело в том, что базу данных можно «обмануть» и выдать локальный вызов за удаленный, чтобы использовать режим проверки сигнатуры. Следующий пример предполагает, что у вас имеется имя службы Oracle Net «localhost» с подключением к локальной базе данных:

CREATE DATABASE LINK loopback
      CONNECT TO bob IDENTIFIED BY swordfish USING 'localhost'
/
CREATE OR REPLACE PROCEDURE volatilecode AS 
BEGIN
   --...
END;
/
CREATE OR REPLACE SYNONYM volatile_syn FOR volatilecode@loopback 
/
CREATE OR REPLACE PROCEDURE save_from_recompile AS 
BEGIN
   ... 
   volatile_syn;
   ...
END;
/

Для использования этой конфигурации в рабочую систему включается вызов следующего вида:

BEGIN
   EXECUTE IMMEDIATE 'ALTER SESSION SET REMOTE_DEPENDENCIES_MODE=SIGNATURE'; 
   save_from_recompile;
END;
/

При условии, что вы не делаете ничего, что бы изменяло сигнатуру volatilecode, код можно изменять и перекомпилировать без перехода save_from_recompile в недействительное состояние или ошибки времени выполнения. Вы даже можете перестроить синоним для совершенно другой процедуры. Такой подход не лишен недостатков; например, если volatilecode выводит что-либо средствами DBMS_OUTPUT, вы не увидите эту информацию, если только save_from_recompile не получает ее явно по каналу связи с базой данных с последующим непосредственным выводом. Но во многих приложениях такие обходные решения оказываются невысокой ценой за повышение доступности.

 

 

Ограничения модели удаленных вызовов Oracle

Вплоть до Oracle11g Release 2 программы PL/SQL не могли непосредственно использовать переменные и константы, курсоры и исключения, находящиеся на удаленных серверах. Причем ограничение касается не только клиентского PL/SQL, вызывающего сервер базы данных, но и межсерверных вызовов удаленных процедур.

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

Обходное решение основано на инкапсуляции курсоров в подпрограммах открытия, выборки и закрытия. Например, если в спецификации серверного пакета book_maint объявлен курсор book_cur, в тело пакета можно поместить такой код:

PACKAGE BODY book_maint 
AS
   prv_book_cur_status BOOLEAN;
   PROCEDURE open_book_cur IS 
   BEGIN
      IF NOT book_maint.book_cur%ISOPEN 
      THEN
         OPEN book_maint.book_cur;
      END IF;
   END;
   FUNCTION next_book_rec RETURN books%ROWTYPE 
   IS
      l_book_rec books%ROWTYPE;
   BEGIN
      FETCH book_maint.book_cur INTO l_book_rec; 
      prv_book_cur_status := book_maint.book_cur%FOUND;
      RETURN l_book_rec;
   END;

   FUNCTION book_cur_is_found RETURN BOOLEAN 
   IS
   BEGIN
      RETURN prv_book_cur_status;
   END;
   PROCEDURE close_book_cur IS 
   BEGIN
      IF book_maint.book_cur%ISOPEN 
      THEN
         CLOSE book_maint.book_cur;
      END IF;
   END;
END book_maint;

К сожалению, этот подход не годится для перехвата и обработки удаленных исключений, поскольку исключения «тип данных» интерпретируются иначе, чем остальные типы данных. Вместо этого придется выполнить процедуру RAISE_APPLICATI0N_ERR0R с пользовательскими номерами исключений от -20 000 до -20 999. О том, как написать пакет для перехвата и обработки исключений этого типа, рассказывалось в этой заметке.

 

 

Перекомпиляция недействительных программ

Кроме недействительности в результате изменения задействованных объектов, новая программа может оказаться в недействительном состоянии в результате неудачной компиляции. В любом случае программа PL/SQL с пометкой INVALID не будет выполняться до тех по, пока успешная перекомпиляция не изменит ее статус на VALID. Перекомпиляция может выполняться одним из трех способов:

  1. Автоматическая перекомпиляция во время выполнения — исполнительное ядро PL/SQL во многих обстоятельствах автоматически перекомпилирует недействительную программу при ее вызове.
  2. Перекомпиляция ALTER...COMPILE — явная перекомпиляция пакета командой ALTER.
  3. Перекомпиляция уровня схемы — использование многочисленных встроенных и внешних решений для перекомпиляции всех недействительных программ в схеме или экземпляре базы данных.

 

Автоматическая перекомпиляция во время выполнения

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

Тогда для чего может понадобиться явная перекомпиляция? Есть две причины:

  •  В среде реальной эксплуатации перекомпиляция по принципу «в нужный момент» может иметь негативные последствия — в отношении как ухудшения производительности, так и каскадного распространения недействительных объектов базы данных. Перекомпиляция всех недействительных программ в то время, пока пользователи не работают с приложением, существенно улучшит их впечатления от работы с приложением (насколько это возможно).
  •  Перекомпиляция программы, которая ранее была выполнена другим пользователем, подключенным к тому же экземпляру, может привести (и обычно приводит) к ошибкам следующего вида:
ORA-04068: existing state of packages has been discarded 
ORA-04061: existing state of package "SCOTT.P1" has been invalidated 
ORA-04065: not executed, altered or dropped package "SCOTT.P1"
ORA-06508: PL/SQL: could not find program unit being called

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

Что делать? Ваше приложение может перехватить исключение, а затем снова вызвать ту же программу. Состояние пакета будет сброшено (на что указывает сообщение ORA- 4068), а база данных сможет выполнить программу. К сожалению, в сеансе также будет сброшено состояние всех пакетов, включая DBMS_OUTPUT и другие встроенные пакеты. Крайне маловероятно, чтобы пользователи после этого смогли продолжить работу с приложением.

Для пользователей приложений на базе PL/SQL это означает то, что при каждой необходимости обновления (перекомпиляции) кода все пользователи должны прервать работу с приложением. В современном мире «постоянно доступных» интернет-приложений такой сценарий неприемлем. В Oracle Database 11g Release 2 эта проблема наконец-то была решена за счет введения поддержки «оперативного обновления» кода приложения.

Основной вывод по поводу автоматической перекомпиляции заслуживает того, чтобы его повторить: до выхода Oracle Database 11g Release 2 в средах реальной эксплуатации не следует делать ничего, что привело бы к перекомпиляции (автоматической или иной) любых хранимых объектов, к экземплярам которых сеанс может обратиться позднее. К счастью, средам разработки обычно не нужно беспокоиться о каскадных эффектах, а автоматическая перекомпиляция вне среды реальной эксплуатации способна существенно упростить задачу разработчика. И хотя перекомпиляция всех недействительных программ может быть полезна (см. далее), этот шаг не столь критичен.

 

Перекомпиляция ALTER ... COMPILE

Программу, ранее откомпилированную в базе данных, всегда можно повторно откомпилировать командой ALTER...COMPILE. Например, в приведенном ранее примере по содержимому словаря данных можно было узнать, что три программных модуля стали недействительными.

Следующие команды перекомпилируют программы, чтобы их статус вернулся в состояние VALID :

ALTER PACKAGE bookworm COMPILE BODY REUSE SETTINGS;
ALTER PACKAGE book COMPILE BODY REUSE SETTINGS;
ALTER PROCEDURE add_book COMPILE REUSE SETTINGS;

Обратите внимание на секцию REUSE SETTINGS. Она гарантирует, что все настройки перекомпиляции (уровень оптимизации, уровень предупреждений и т. д.), ранее связанные с этой программой, останутся неизменными. При отсутствии REUSE SETTINGS после перекомпиляции будут применены текущие настройки сеанса.

Конечно, при большом количестве недействительных объектов вводить команды ALTER COMPILE одну за одной не хочется. Конечно, можно сгенерировать все команды ALTER простым запросом:

SELECT 'ALTER ' || object_type || ' ' || object_name 
         || ' COMPILE REUSE SETTINGS;'
      FROM user_objects 
   WHERE status = 'INVALID'

Но у такого решения есть один недостаток: перекомпиляция одного недействительного объекта может привести к тому, что несколько других объектов будут помечены как недействительные. Гораздо лучше воспользоваться другими, более сложными методами перекомпиляции всех недействительных программ; они будут рассмотрены ниже.

 

Перекомпиляция уровня схемы

Oracle предоставляет несколько способов перекомпиляции всех недействительных программ в конкретной схеме. Все перечисленные ниже инструменты должны запускаться с привилегиями SYSDBA, если явно не указано обратное. Все перечисленные файлы находятся в каталоге $ORACLE_HOME/Rdbms/Admin.

  •  utlip.sql — объявляет недействительным и перекомпилирует весь код PL/SQL и представления во всей базе данных. (На самом деле создает некоторые структуры данных, объявляет объекты недействительными и предлагает перезапустить базу данных и выполнить utlrp.sql.)
  •  utlrp.sql — последовательно перекомпилирует все недействительные объекты. Хорошо подходит для однопроцессорных машин; на многопроцессорных машинах следует использовать utlrcmp.sql.
  •  utlrcmp.sql — как и utlrp.sql, перекомпилирует все недействительные объекты, но делает это параллельно; работа основана на отправке нескольких запросов на перекомпиляцию в очередь заданий базы данных. «Степень параллелизма» может передаваться в целочисленном аргументе командной строки. Если аргумент не указан или равен 0, сценарий пытается выбрать подходящую степень параллелизма самостоятельно. Тем не менее Oracle предупреждает о том, что параллельная версия может не обеспечить кардинального выигрыша по производительности из-за конкуренции за возможность записи в системные таблицы.
  •  DBMS_UTILITY.REC0MPILE_SCHEMA — процедура существует начиная с Oracle8 Database и может запускаться из любой схемы; привилегии SYSDBA для этого не нужны. Процедура перекомпилирует программы в заданной схеме. Ее заголовок определяется следующим образом:
DBMS_UTILITY.COMPILE_
      SCHEMA ( schema VARCHAR2
   , compile_all BOOLEAN DEFAULT TRUE,
   , reuse_settings BOOLEAN DEFAULT FALSE
);
  • До выхода Oracle Database 10g процедура была реализована с ошибкой и часто объявляла недействительными столько новых программ, сколько перекомпилировала в состояние VALID. Похоже, теперь она работает как положено.
  •  UTL_RECOMP — этот встроенный пакет, появившийся в Oracle Database 10g, проектировался для обновлений или исправлений базы данных, требовавших значительной перекомпиляции. Он содержит две программы: одна перекомпилирует недействительные объекты последовательно, а другая использует DBMS_3OB для проведения параллельной перекомпиляции. Например, чтобы перекомпилировать все недействительные объекты в экземпляре базы данных в параллельном режиме, администратору достаточно ввести одну простую команду:
UTL_RECOMP.recomp_parallel

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

Пример вызова последовательной версии для перекомпиляции всех недействительных объектов в схеме SCOTT :

CALL UTL_RECOMP.recomp_serial ('SCOTT');

В системе с несколькими процессорами параллельная версия может ускорить перекомпиляцию. Но как указано в документации этого пакета, компиляция хранимых программ приводит к обновлению многих каталоговых структур и сопряжена с интенсивным вводом/выводом; вероятно, повышение скорости будет зависеть и от скорости ваших дисков.

Следующий пример запрашивает перекомпиляцию всех недействительных объектов в схеме SCOTT, с использованием до четырех параллельных потоков для перекомпиляции:

CALL UTL_RECOMP.recomp_parallel ('SCOTT', 4);

Соломон Якобсон, выдающийся администратор баз данных Oracle и специалист в области компьютерных технологий, также написал программу перекомпиляции, которая может использоваться для перекомпиляции всех недействительных программ в порядке зависимостей. Она работает с хранимыми программами, представлениями (включая материализованные), триггерами и пользовательскими объектными типами. Программа находится в файле recompile.sql на сайте github.

 

Предотвращение объявления недействительных зависимостей 

 

Вас заинтересует / Intresting for you:

Управление приложениями PL/SQL...
Управление приложениями PL/SQL... 3112 просмотров Stas Belkov Thu, 16 Jul 2020, 06:20:48
Встроенные методы коллекций PL...
Встроенные методы коллекций PL... 7023 просмотров sepia Tue, 29 Oct 2019, 09:54:01
Работа с числами в PL/SQL на п...
Работа с числами в PL/SQL на п... 16470 просмотров Antoniy Mon, 28 May 2018, 16:45:11
Символьные функции и аргументы...
Символьные функции и аргументы... 10872 просмотров Анатолий Wed, 23 May 2018, 18:54:01
Войдите чтобы комментировать

OraCool аватар
OraCool ответил в теме #9506 08 окт 2019 05:38
Хотя автоматическое управление зависимостями Oracle избавляет разработчика от многих хлопот, к обновлению приложений на реально используемой базе данных следует относиться в высшей степени осторожно из-за необходимости блокировки объектов и сброса состояния пакетов.