ГЛАВА 9

        ----------------------------------------------------------------

        УПРАВЛЕНИЕ ЗАВИСИМОСТЯМИ МЕЖДУ ОБЪЕКТАМИ СХЕМЫ



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

            *  использование пакетов для минимизации зависимостей

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

            *  вывод информации управления зависимостями

        Информация  о  хранимых  процедурах  и  пакетах  в  этой   главе
        применима  лишь  к  тем  системам,  которые  используют ORACLE с
        процедурной  опцией.   Если   вы  используете  Trusted   ORACLE,
        обратитесь   также   к   документу   Trusted   ORACLE7    Server
        Administrator's Guide для информации об управлении зависимостями
        в этом окружении.



































                     Управление зависимостями между объектами схемы  9-1


----------------

Вопросы зависимостей

        Когда  вы   создаете  хранимую   процедуру  или   пакет,  ORACLE
        проверяет,  что  операции,  которые  выполняет эта процедура или
        пакет, возможны  с точки  зрения доступа  к адресуемым объектам.
        Например, если хранимая  процедура содержит предложение  SELECT,
        выбирающее  столбцы  из  таблицы,  то  ORACLE проверяет, что эта
        таблица существует и  содержит указанные столбцы.   Если таблица
        впоследствии  переопределяется  так,  что  один  из  ее столбцов
        перестает существовать,  то хранимая  процедура может  перестать
        правильно  работать.    По  этой   причине  хранимая   процедура
        называется ЗАВИСИМОЙ от данной таблицы.

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


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

        Избегайте перекомпиляции хранимых процедур, функций и пакетов во
        время  выполнения  ваших  приложений.   Такая  перекомпиляция не
        только  ухудшает  производительность;  хуже того, результирующие
        ошибки компиляции могут помешать использованию ваших приложений.
        Чтобы  избежать  перекомпиляций  времени  выполнения, соблюдайте
        следующие правила:

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

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

               Вы можете  внучную перекомпилировать  процедуру, хранимую
               функцию или пакет с  помощью опции COMPILE команды  ALTER
               PROCEDURE,  ALTER  FUNCTION   или  ALTER  PACKAGE.    Для
               дополнительной информации об  этих командах обратитесь  к
               документу ORACLE7 Server SQL Language Reference Manual.










9-2  Руководство разработчика приложений


               Вы можете определить  зависимости между объектами  схем в
               вашей базе данных, запустив скрипт UTLDTREE.SQL.   Точное
               имя  и  местоположение  этого  скрипта  может зависеть от
               вашей операционной системы.  Дополнительная информация  о
               том,  как  использовать  этот  скрипт, приведена в тексте
               самого скрипта.

            *  Пакетируйте  процедуры  и  функции,  когда  это возможно.
               Если процедура или функция размещена в пакете, вы  можете
               модифицировать  ее   определение,  не   заставляя  ORACLE
               перекомпилировать  другие  процедуры  и  функции, которые
               вызывают ее.

        Есть несколько вопросов, касающихся зависимостей, которые должны
        рассматриваться  перед  тем,  как  удалять  процедуру или пакет.
        Дополнительная  информация   об  этих   вопросах  содержится   в
        документе  ORACLE7  Server  Concepts  Manual.   Ниже   приведены
        некоторые рекомендации по управлению зависимостями.


        СТАРАЙТЕСЬ   ИСПОЛЬЗОВАТЬ   ПАКЕТЫ.    Пакеты   дают    наиболее
        эффективный метод предотвращения излишних проверок зависимостей.
        Следующий пример иллюстрирует преимущества пакетов.

        Предположим следующую ситуацию:

            *  Независимая  процедура  PROC  зависит  от  пакетированной
               процедуры PACK_PROC.

            *  Определение процедуры PACK_PROC изменяется, и тело пакета
               перекомпилируется.

            *  Спецификация процедуры PACK_PROC в спецификации пакета не
               изменяется.

        Несмотря на то,  что тело пакета  перекомпилировано, независимая
        процедура PROC, зависимая от пакетированной процедуры PACK_PROC,
        не  становится  недействительной  и  не  требует перекомпиляции,
        потому что спецификация процедуры PACK_PROC не изменилась.

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

        Каждый  раз,  когда  вы  перекомпилируете  процедуру,  вы должны
        проконсультироваться  с  администраторами  других  баз  данных и
        разработчиками приложений, чтобы идентифицировать все  удаленные
        зависимые  процедуры  и   обеспечить  их  перекомпиляцию.    Это
        позволит избежать  перекомпиляций во  время выполнения  и выявит
        любые возможные ошибки компиляции, которые в ином случае были бы
        выданы  пользователю  приложения;  для дополнительной информации
        обратитесь  к  секции  "Ручная  перекомпиляция  недействительных
        обзоров, процедур, пакетов и триггеров" на странице 9-4.








                     Управление зависимостями между объектами схемы  9-3


        АТРИБУТЫ  %TYPE  И  %ROWTYPE.   Атрибут  %TYPE предоставляет тип
        данных переменной, константы или столбца.  Этот атрибут особенно
        полезен  при  объявлении  переменной  или  аргумента процедуры с
        типом данных,  зависящим от  определения столбца  в таблице базы
        данных.   Атрибут  %ROWTYPE  полезен,  когда  вы хотите объявить
        переменную-запись, которая должна  иметь такую же  же структуру,
        что  и  строка  в  таблице  или обзоре, или строка, возвращаемая
        извлечением из курсора.

        Объявление  конструктов  через  атрибуты  %TYPE И %ROWTYPE имеет
        следующие достоинства и недостатки.

            *  Вы  не  обязаны  знать  тип  данных столбца или структуру
               таблицы.  Например, список аргументов процедуры,  которая
               вставляет  строку  в  таблицу  EMP,  мог бы быть объявлен
               следующим образом:

               CREATE PROCEDURE hire_fire(emp_record emp%ROWTYPE) AS ...

               Если вы измените типы столбцов или структуру таблицы,  то
               конструкты, определенные по этим типам или по  структуре,
               автоматически изменятся соответствующим образом.

            *  Когда  вы  определяете  конструкт  через  ОБЪЕКТ%TYPE или
               ОБЪЕКТ%ROWTYPE,  этот  конструкт  становится зависимым от
               ОБЪЕКТА.  Если ОБЪЕКТ  изменяется, все зависимые  от него
               конструкты становятся недействительными.

        Коротко говоря,  атрибуты %TYPE  и %ROWTYPE  позволяют устранить
        один тип зависимости, но создают другой.


----------------

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

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

        Принудительная   (форсированная)   перекомпиляция   чаще   всего
        используется  для  того,   чтобы  проверить  на   ошибки,  когда
        известно, что зависимый объект недействителен, но он временно не
        используется; в таком  случае для автоматической  перекомпиляции
        пришлось бы дожидаться очередного обращения к объекту.

        Чтобы  идентифицировать   недействительные  зависимые   объекты,
        опросите  обзоры  USER_/ALL_/DBA_OBJECTS;  примеры  приведены  в
        секции "Вывод информации  управления зависимостями" на  странице
        9-6.










9-4  Руководство разработчика приложений


Ручная перекомпиляция обзоров
-----------------------------
        Чтобы перекомпилировать обзор, используйте команду ALTER VIEW  с
        параметром    COMPILE.     Например,    следующее    предложение
        перекомпилирует обзор EMP_DEPT, содержащийся в вашей схеме:

        ALTER VIEW emp_dept COMPILE;

Привилегии, требуемые для ручной перекомпиляции обзоров

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

Ручная перекомпиляция процедур и функций
----------------------------------------
        Чтобы  перекомпилировать  независимую  процедуру  или   функцию,
        используйте  команду   ALTER  PROCEDURE/FUNCTION   с  параметром
        COMPILE.    Например,   следующее   предложение  перекомпилирует
        хранимую процедуру UPDATE_SALARY, содержащуюся в вашей схеме:

        ALTER PROCEDURE update_salary COMPILE;

Ручная перекомпиляция пакетов
-----------------------------
        Чтобы  перекомпилировать   тело  пакета   или  тело   вместе  со
        спецификацией  пакета,  используйте  команду  ALTER  PACKAGE   с
        параметром    COMPILE.     Например,    следующие    предложения
        перекомпилируют  только  тело  и  тело  со  спецификацией пакета
        ACCT_MGMT_PACKAGE, соответственно:

        ALTER PACKAGE acct_mgmt_package COMPILE BODY;

        ALTER PACKAGE acct_mgmt_package COMPILE PACKAGE;

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

        EXECUTE DBMS_UTILITY.COMPILE_ALL;

Привилегии, требуемые для ручной перекомпиляции процедур или пакетов

        Для ручной  перекомпиляции независимой  процедуры или  пакета вы
        должны  либо  иметь  ее  (его)  в  своей  схеме,  либо  обладать
        системной привилегией ALTER ANY PROCEDURE.

Ручная перекомпиляция триггеров
-------------------------------

        Чтобы  перекомпилировать  существующий  триггер,  независимо  от
        того, включен от или выключен, используйте команду ALTER TRIGGER
        с параметром COMPILE.  Например, следующее предложение форсирует
        компиляцию триггера с именем REORDER:

        ALTER TRIGGER reorder COMPILE;

Привилегии, требуемые для ручной перекомпиляции триггеров

        Для ручной перекомпиляции  триггера вы должны  либо иметь его  в
        своей  схеме,  либо  обладать  системной  привилегией  ALTER ANY
        TRIGGER.

                     Управление зависимостями между объектами схемы  9-5


----------------

Вывод информации управления зависимостями

        Следующие  обзоры  словаря  данных  выдают  информацию  о прямых
        зависимостях и об управлении зависимостями:

            *  USER_ \ ALL_ \ DBA_DEPENDENCIES

            *  USER_ \ ALL_ \ DBA_OBJECTS

        Замечание:  Для  полного  описания  этих  обзоров словаря данных
        обратитесь к приложению D.

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

        CREATE TABLE emp . . . ;

        CREATE PROCEDURE hire_emp BEGIN . . . END;

        ALTER TABLE emp . . . ;


Пример 1: Вывод состояния объекта

        Обзор  словаря  данных  ALL_OBJECTS  выдает  информацию обо всех
        объектах,  доступных  текущему  пользователю,  включая состояние
        каждого объекта (действителен он или недействителен).  Например,
        следующий запрос  выдает имя,  тип и  текущее состояние  каждого
        объекта, доступного текущему пользователю базы данных:

        SELECT object_name, object_type, status
            FROM all_objects;

        Этот запрос возвратит информацию, подобную следующей:

        OBJECT_NAME     OBJECT_TYPE     STATUS
        --------------- --------------- ------------
        EMP             TABLE           VALID
        HIRE_EMP        PROCEDURE       INVALID


Пример 2: Вывод зависимостей

        Обзор  словаря  данных  DBA_DEPENDENCIES  выдает  все  зависимые
        объекты в  базе данных,  и все  объекты, от  которых они зависят
        непосредственно.    Например,   следующий   запрос   выдает  все
        зависимые объекты в схеме пользователя JWARD:

        SELECT name, type, referenced_name, referenced_type
            FROM sys.dba_dependencies
            WHERE owner = 'JWARD';

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

        NAME        TYPE         REFERENCED_NAME     REFERENCED_TYPE
        ----------- ------------ ------------------- -------------------
        HIRE_EMP    PROCEDURE    EMP                 TABLE


9-6  Руководство разработчика приложений


Утилита отслеживания зависимостей
---------------------------------

        Обзоры     словаря     данных    USER_ \ ALL_ \ DBA_DEPENDENCIES
        предоставляют  информацию  лишь  о  непосредственной зависимости
        объектов.   В  дополнение   к  этому,  вы   можете  использовать
        специальную утилиту отслеживания зависимостей, чтобы выдать  как
        прямые, так и косвенные зависимости для объекта.

        Чтобы  создать  утилиту  отслеживания  зависимостей,   выполните
        скрипт  UTLDTREE.SQL.   Местоположение  этого  файла  зависит от
        операционной  системы.   Скрипт  UTLDTREE.SQL  создает следующие
        объекты схемы:

Таблица DEPTREE_TEMPTAB
        Структура:      object_id             NUMBER
                        referenced_object_id  NUMBER
                        nest_level            NUMBER
                        seq#                  NUMBER

        Временная  таблица,  используемая  для  хранения  информации   о
        зависимостях, возвращаемой процедурой DEPTREE_FILL.

Обзор DEPTREE
        Имена столбцов: nested_level,object_type,owner,object_name,seq#

        Обзор,  который  выдает  информацию  о  зависимостях  по таблице
        DEPTREE_TEMPTAB.   Родительский  объект  имеет  нулевое значение
        NESTED_LEVEL,   зависимые   объекты   имеют   ненулевые значения
        NESTED_LEVEL.

Обзор IDEPTREE
        Имя столбца: dependencies

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

Последовательность DEPTREE_SEQ
        Последовательность,  используемая  для  уникальной идентификации
        наборов зависимостей, хранящихся в таблице DEPTREE_TEMPTAB.

Процедура DEPTREE_FILL
        Синтаксис: DEPTREE_FILL (object_type CHAR, object_owner CHAR,
                                 object_name CHAR)

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

Использование UTLDTREE в режиме INTERNAL

        Если  вы  запускаете  скрипт  UTLDTREE.SQL и используете утилиту
        отслеживания  зависимостей,   подключившись  как   INTERNAL,  то
        собирается  выдается  информация  о  зависимостях  не только для
        зависимых объектов, но также для зависимых курсоров (разделяемых
        областей SQL).

                     Управление зависимостями между объектами схемы  9-7


Пример

        Следующий пример показывает, как применять утилиту UTLDTREE  для
        отслеживания зависимостей объекта.  Предположим, что были выданы
        следующие предложения SQL:

        CONNECT scott/tiger;

        CREATE TABLE scott.emp ( ... );

        CREATE SEQUENCE scott.emp_sequence;

        CREATE VIEW scott.sales_employees AS
          SELECT * FROM scott.emp WHERE deptno = 10;

        CREATE PROCEDURE scott.hire_salesperson (name VARCHAR2,
          job VARCHAR2, mgr NUMBER, hiredate DATE, sal NUMBER,
          comm NUMBER)
        IS
        BEGIN
          INSERT INTO scott.sales_employees
            VALUES (scott.emp_sequence.NEXTVAL, name, job, mgr,
              hiredate, sal, comm, 10);
        END;

        CREATE PROCEDURE scott.fire_salesperson (emp_id NUMBER) IS
        BEGIN
          DELETE FROM scott.sales_employees WHERE empno = emp_id;
        END;

        SELECT * FROM scott.emp;

        SELECT * FROM scott.sales_employees;

        EXECUTE scott.hire_salesperson ('ARNALL', 'MANAGER', 7839, \
                                        SYSDATE, 1000, 500);

        EXECUTE scott.fire_salesperson (7934);

        Допустим, SCOTT хочет изменить (ALTER) таблицу EMP, и перед этим
        он   хотел   бы   узнать,   какие   зависимые   объекты   станут
        недействительными в результате изменения таблицы EMP.  Следующий
        вызов процедуры заполнит  таблицу DEPTREE_TEMPTAB информацией  о
        зависимостях,  относящихся  к  таблице  EMP (предполагается, что
        этот вызов осуществляется из SQL*DBA):

        EXECUTE deptree_fill('TABLE', 'SCOTT', 'EMP');
















9-8  Руководство разработчика приложений


        Следующие  два  запроса  показывают  информацию  о зависимостях,
        собранную этим вызовом для таблицы EMP:

        SELECT * FROM deptree;

        NESTED_LEV TYPE       OWNER          NAME               SEQ#
        ---------- ---------- -------------- ------------------ --------
                 0 TABLE      SCOTT          EMP                       0
                 1 VIEW       SCOTT          SALES_EMPLOYEES           1
                 2 PROCEDURE  SCOTT          FIRE_SALESPERSON          2
                 3 PROCEDURE  SCOTT          HIRE_SALESPERSON          3

        SELECT * FROM ideptree;

        DEPENDENCIES
        ----------------------------------------
        TABLE SCOTT.EMP
           VIEW SCOTT.SALES_EMPLOYEES
              PROCEDURE SCOTT.FIRE_SALESPERSON
              PROCEDURE SCOTT.HIRE_SALESPERSON

        Альтернативно, с помощью утилиты UTLDTREE вы можете выявить  все
        курсоры,  которые  зависят   от  таблицы  EMP   (т.е.  зависимые
        разделяемые области  SQL, которые  в данный  момент находятся  в
        разделяемом пуле).   Для этого  подключитесь к  базе данных  как
        INTERNAL  и  выполните  процедуру  DEPTREE_FILL, как выше; затем
        выдайте следующие два запроса:

        SELECT * FROM deptree;

NESTED_LEV TYPE       OWNER          NAME                           SEQ#
---------- ---------- -------------- ------------------------------ ----
         0 TABLE      SCOTT          EMP                               0
         1 CURSOR            "select * from scott.emp"       0.5
         2 CURSOR            "select * from scott.sales_emp  7.5
         3 CURSOR            "BEGIN hire_salesperson ('ARNA  9.5
         3 CURSOR            "BEGIN fire_salesperson (7934)  9.5

        SELECT * FROM ideptree;

        DEPENDENCIES
        ----------------------------------------------------------------
        TABLE SCOTT.EMP
           CURSOR ."select * from scott.emp"
              CURSOR ."select * from scott.sales_employees"
                 CURSOR ."BEGIN hire_salesperson ('ARNALL', 'MAN
                    CURSOR ."BEGIN fire_salesperson (7934) END"