Шаг 95 - PL/SQL - Хранимые процедуры, объявления, зависимости

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

Хранимые подпрограммыЛокальные подпрограммы
Хранятся в БД в скомпилированном p-коде, при вызове процедуру не нужно компилировать.Компилируются фрагменты и содержащиеся в них блоки. При повторном выполнении производится новая компиляция.
Могут вызываться из любого блока запущенного на выполнение пользователем который имеет привилегии EXECUTE для данной подпрограммы.Могут вызываться только из содержащего их блока.
Код подпрограммы хранится отдельно от вызывающего блока, по этому вызывающий блок короче и легче для понимания. Кроме того, при желании с подпрограммой и вызывающим блоком можно работать по отдельности.Подпрограмма и вызывающий блок находятся в одном месте, что может привести к путанице. Если изменения вносятся в вызывающий блок то подпрограмму необходимо компилировать заново.
Скомпилированный p-код можно закрепить в разделяемом пуле при помощи модульной процедуры DBMS_SHARED_POOL.KEEP. Это приводит к повышению производительности системы в целом.Непосредственно локальные подпрограммы нельзя закреплять в разделяемом пуле.

Вот собственно кратко различия, между двумя видами программных блоков. А теперь давайте поговорим на тему, зависимости объектов БД. Дело в том, что при компиляции процедуры или функции, как и все объекты Oracle, на которые производится ссылки записываются в словарь данных. Возникает так называемая зависимость (depend) объектов друг от друга. Давайте рассмотрим это на примере. Пусть, скажем, имеется таблица TBLA, (создадим ее):

CREATE TABLE TBLA(
	FIELDA VARCHAR2(100),
	FIELDB NUMBER(3,5)
	)
/

Получаем:

SQL> CREATE TABLE TBLA(
  2   FIELDA VARCHAR2(100),
  3   FIELDB NUMBER(3,5)
  4   )
  5  /

Таблица создана.

Предположим что, после этого вы создаете процедуру такого вида:

CREATE PROCEDURE TEST_DEPEND(PRMA IN TBLA.FIELDA%TYPE, PRMB IN TBLA.FIELDB%TYPE)
IS

BEGIN

NULL;

END TEST_DEPEND;
/

Получаем после компиляции:

SQL> CREATE PROCEDURE TEST_DEPEND(PRMA IN TBLA.FIELDA%TYPE, PRMB IN TBLA.FIELDB%TYPE)
  2  IS
  3  
  4  BEGIN
  5  
  6  NULL;
  7  
  8  END TEST_DEPEND;
  9  /

Процедура создана.

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

SELECT OBJECT_NAME, OBJECT_TYPE, STATUS 
FROM USER_OBJECTS
WHERE OBJECT_NAME IN ('TBLA','TEST_DEPEND')
/

Получаем:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS
  2  FROM USER_OBJECTS
  3  WHERE OBJECT_NAME IN ('TBLA','TEST_DEPEND')
  4  /

OBJECT_NAME      OBJECT_TYPE        STATUS
---------------- ------------------ -------
TEST_DEPEND      PROCEDURE          VALID
TBLA             TABLE              VALID

Все прекрасно, но это только пока. Допустим по каким-либо причинам вы изменили таблицу TBLA вот так:

ALTER TABLE TBLA ADD FIELDC NUMBER(5,7)
/

Получаем в результате:

SQL> ALTER TABLE TBLA ADD FIELDC NUMBER(5,7)
  2  /

Таблица изменена.

А вот теперь, если посмотреть на состояние объектов, то мы увидим следующее:

SELECT OBJECT_NAME, OBJECT_TYPE, STATUS 
FROM USER_OBJECTS
WHERE OBJECT_NAME IN ('TBLA','TEST_DEPEND')
/

Получаем:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS
  2  FROM USER_OBJECTS
  3  WHERE OBJECT_NAME IN ('TBLA','TEST_DEPEND')
  4  /

OBJECT_NAME    OBJECT_TYPE        STATUS
-------------- ------------------ -------
TEST_DEPEND    PROCEDURE          INVALID
TBLA           TABLE              VALID

Ууупс! (Как поет Бритни Спирс) А, процедура то TEST_DEPEND стала INVALID! Что же делать?! Может вернуть все на круги своя? Пробуем:

ALTER TABLE TBLA DROP COLUMN FIELDC
/

Получаем:

SQL> ALTER TABLE TBLA DROP COLUMN FIELDC
  2  /

Таблица изменена.

Снова смотрим состояние объекта:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS
  2  FROM USER_OBJECTS
  3  WHERE OBJECT_NAME IN ('TBLA','TEST_DEPEND')
  4  /

OBJECT_NAME   OBJECT_TYPE        STATUS
------------- ------------------ -------
TEST_DEPEND   PROCEDURE          INVALID
TBLA          TABLE              VALID

Ууупс! (I did it again!) Не помогло! Что же делать? Да все просто! Если изменили связанный объект, нужно перекомпилировать вашу процедуру! Вот так:

ALTER PROCEDURE TEST_DEPEND COMPILE
/

Получаем:

SQL> ALTER PROCEDURE TEST_DEPEND COMPILE
  2  /

Процедура изменена.

А теперь убедимся, что все пришло на круги своя! Даем запрос:

SQL> SELECT OBJECT_NAME, OBJECT_TYPE, STATUS
  2  FROM USER_OBJECTS
  3  WHERE OBJECT_NAME IN ('TBLA','TEST_DEPEND')
  4  /

OBJECT_NAME    OBJECT_TYPE        STATUS
-------------- ------------------ -------
TEST_DEPEND    PROCEDURE          VALID
TBLA           TABLE              VALID

Надеюсь, ясно, если один объект БД связан с другим и в какой-то момент при изменении одного из них с помощью оператора DDL или как-либо еще - другой объект необходимо переинициализировать! Немного не удобно, зато дешево и сердито! В любом случае учитесь сопровождать свой код, так чтобы не было ошибок! :)


Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Летучий Сергей.