Для ясности картины давайте подведем некую черту под, классификацией хранимых и локальных (анонимных или неименованных) процедурах. Скажу сразу, старайтесь как можно больше использовать именно хранимые подпрограммы (процедуры и функции), а анонимные блоки, только в процессе создания и отладки. Вот таблица, для их сравнения:
Хранимые подпрограммы | Локальные подпрограммы |
---|---|
Хранятся в БД в скомпилированном 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 или как-либо еще - другой объект необходимо переинициализировать! Немного не удобно, зато дешево и сердито! В любом случае учитесь сопровождать свой код, так чтобы не было ошибок! :)