原文整理自:http://www.51testing.com/?uid-16403-action-viewspace-itemid-98161;http://www.eygle.com/archives/2005/01/ecioaeaoeeeaoea.html
先看個文章:http://www.itpub.net/thread-1112553-1-1.html
每次資料庫做了更新(打各種資料庫方面的更新檔後,不是資料庫本身的更新,是各種對象改變增加修改等,呵呵不,别誤解)
完了以後我都要查一下資料庫中的失效對象,每次都發現多了好多,尤其是包啊過程啊等,都要重新再編譯一次,才全部都好了,有點奇怪,為什麼總需要這樣呢?
大家有這樣的經曆把,隻要重新編譯就OK了,不這樣做,生産中一堆失效對象,不編譯估計對生産有影響吧,系統用到這些包和過程等的時候,發現失效會自己去編譯嗎?
跟帖解答:你修改對象的操作導緻了存儲過程被置于invalid 狀态。因為更新有一些DDL操作,導緻相關存儲過程失效。可以使用自帶的重編譯腳本$ORACLE_HOME/rdbms/admin/utlrp.sql ,存儲過程再次使用的時候自動編譯。但是,自動編譯可能成功也可能失敗,
更新完檢查失效對象是好習慣。
更好的習慣是,更改對象之前先檢視會影響哪些對象
1、查找無效對象
SQL> COLUMN object_name FORMAT A30
SQL> SELECT owner,object_type,object_name,STATUS
FROM dba_objects WHERE
STATUS='INVALID' ORDER BY owner,object_type,object_name;
2、手動編譯
如果無效對象的數量很少,那麼你可以逐個編譯這些對象.
如:
SQL> ALTER PACKAGE my_package COMPILE;
SQL> ALTER PACKAGE my_package COMPILE BODY;
SQL> ALTER PROCEDURE my_procedure COMPILE;
SQL> ALTER FUNCTION my_function COMPILE;
SQL> ALTER TRIGGER my_trigger COMPILE;
SQL> ALTER VIEW my_view COMPILE;
你也可以用DBMS_DDL包來編譯(但隻用于PL/SQL對象,是以你不用它來編譯視圖等):
SQL> EXEC DBMS_DDL('PACKAGE','MY_SCHEMA','MY_PACKAGE');
SQL> EXEC DBMS_DDL('PACKAGE BODY','MY_SCHEMA','MY_PACKAGE');
SQL> EXEC DBMS_DDL('PROCEDURE','MY_SCHEMA','MY_PROCEDURE');
SQL> EXEC DBMS_DDL('FUNCTION','MY_SCHEMA','MY_FUNCTION');
SQL> EXEC DBMS_DDL('TRIGGER','MY_SCHEMA','MY_TRIGGER');
3、通用腳本
在某些情況下你可能有很多無效對象要編譯,這樣話手工編譯就顯得效率太低了.
在這種情況下你可以些一個通用的腳本生成編譯腳本.
下面的腳本用來查詢無效的package 和package body并生成便宜這些對象的腳本.
但是這方法不會考慮ORACLE對象之間的依賴關系.
SQL>
SET SERVEROUTPUT ON SIZE 1000000
SQL> BEGIN
FOR cur_rec IN (SELECT owner,object_name,object_type,DECODE (object_type,'PACKAGE',1,'PACKAGE BODY',2,2) AS recompile_order FROM dba_objects WHERE object_type IN ('PACKAGE','PACKAGE BODY') AND STATUS!='VALID' ORDER BY 4) LOOP
BEGIN
IF cur_rec.object_type='PACKAGE ' THEN
EXECUTE IMMEDIATE 'ALTER '||cur_rec.object_type||'
"'||cur_rec.owner||'"."'||cur_rec.object_name||'" COMPILE';
ElSE
EXECUTE IMMEDIATE'ALTER PACKAGE
"'||cur_rec.owner||'"."'||cur_rec.object_name||'" COMPILE BODY';
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line(cur_rec.object_type||' : '||cur_rec.owner||' :
'||cur_rec.object_name);
END;
END LOOP;
END;
/
4、使用DBMS_UTILITY.compile_schema
使用這個包将會編譯指定schema下的所有procedures, functions, packages, and triggers.
你可以在sqlplus 下使用它,如:
SQL> EXEC DBMS_UTILITY.compile_schema(schema => ‘SCOTT’);
5、使用UTL_RECOMP
UTL_RECOMP包有兩個存儲過程:RECOMP_SERIAL 和 RECPMP_PARALLEL
從存儲過程的名字可以看出一個是非并行,一個是并行方式.
使用并行方式會加快編譯速度,包的定義如下:
PROCEDURE RECOMP_SERIAL(
schema IN VARCHAR2 DEFAULT NULL,
flags IN PLS_INTEGER DEFAULT 0);
PROCEDURE RECOMP_PARALLEL
threads IN PLS_INTEGER DEFAULT NULL,
參數使用方法:
schema
- 想編譯的模式,如果為NULL,将編譯資料庫的所有無效對象.
threads
- 并行度,如果為NULL,會使用參數job_queue_processes的值.
通常threads的值最好和CPU的數量想比對,以發揮并行的最大優勢.
flags
-- Schema level.EXEC UTL_RECOMP.recomp_serial('SCOTT');
SQL> EXEC UTL_RECOMP.recomp_parallel(4,'SCOTT');
-- Database level.EXEC UTL_RECOMP.recomp_serial();
SQL> EXEC UTL_RECOMP.recomp_parallel(4);
-- Using job_queue_processes value.EXEC UTL_RECOMP.recomp_parallel();
SQL> EXEC UTL_RECOMP.recomp_parallel(NULL,'SCOTT');
UTL_RECOMP包的一些使用限制
(1).并行執行使用的是job隊列.當運作并行編譯的時候所有job都會被diable直到編譯完成.
(2).包必須在sqlplus中以sys使用者或者有sysdba權限的使用者運作.
(3).UTL_RECOMP依賴于DBMS_STANDARD,DBMS_JOB,DBMS_RANDOM
(4).如果在運作這個包的時候執行DDL語句可能會導緻死鎖.
6、utlrp.sql 和 utlprp.sql
utlrp和utlprp腳本可以用來重編譯資料庫的所有無效對象.通常我們會在Oracle的更新指導中看到這個腳本,Oracle強烈推薦在migration/upgrade/downgrade之後,通過運作此腳本編譯失效對象.
腳本位于$ORACLE_HOME/rdbms/admin目錄.你可以看到utlrp.sql隻是調用utlprp.sql, utlrp.sql在調用utlprp.sql的時候會傳遞給它一個參數,預設為0,這個參數其實就是并行度,其實utlprp.sql調用的是utl_recomp.recomp_parallel:
- 基于CPU_COUNT參數設定并行度.
1 - 以串行方式編譯對象,一次編譯一個.
N - 以N個并行度進行編譯.
腳本需要以sys使用者或者有sysdba權限的使用者來運作,并且當時資料庫中最好不要有活動事物或DDL操作,否則極容易導緻死鎖的出現(這是很容易了解的)
自動編譯可能成功也可能失敗。