誤刪 PROCEDURE/FUNCTION/PACKAGE 後,若無版控備份,可嘗試三種層級遞進的恢復手段:閃回查詢(最簡)、基表歷史(中階)、ODU 磁碟掃描(終極)。本文以實測案例完整記錄。
CONN roger/roger
CREATE OR REPLACE PROCEDURE proc_test_drop AS
BEGIN
FOR x IN (SELECT SYSDATE FROM DUAL) LOOP
DBMS_OUTPUT.PUT_LINE(x.SYSDATE);
END LOOP;
END;
/
EXEC proc_test_drop; -- 正常執行
-- 查詢原始碼
SELECT TEXT, NAME FROM DBA_SOURCE WHERE OWNER='ROGER' AND NAME='PROC_TEST_DROP';
-- 誤刪
DROP PROCEDURE proc_test_drop;
SELECT TEXT FROM DBA_SOURCE WHERE OWNER='ROGER' AND NAME='PROC_TEST_DROP'; -- no rows
前提:UNDO_RETENTION 足夠、UNDO 表空間未被覆寫、具備 FLASHBACK ANY TABLE 權限。
CONN / AS SYSDBA
-- 以 5 分鐘前時間點查詢
SELECT TEXT FROM DBA_SOURCE AS OF TIMESTAMP SYSDATE - 5/60/24
WHERE OWNER='ROGER' AND NAME='PROC_TEST_DROP';
輸出:完整原始碼 8 行,直接複製重建即可。
針對 SYS.OBJ$、SYS.SOURCE$ 直接閃回,繞過視圖限制。
2013-08-06 02:40:00)。OBJ#:
SELECT OBJ# FROM OBJ$ AS OF TIMESTAMP TO_TIMESTAMP('2013-08-06 02:40:00','YYYY-MM-DD HH24:MI:SS')
WHERE NAME='PROC_TEST_DROP'; -- 返回 52148
SET LONG 9999999
SELECT SOURCE FROM SOURCE$ AS OF TIMESTAMP TO_TIMESTAMP('2013-08-06 02:40:00','YYYY-MM-DD HH24:MI:SS')
WHERE OBJ# = 52148 ORDER BY LINE;
同樣可獲得完整原始碼。
適用於 UNDO 已覆寫、資料庫無法開啟、系統表空間損壞的極端場景。
UNLOAD DICT(載入 OBJ$、USER$ 等)。SCAN EXTENT PARALLEL 2。SOURCE$ 表:UNLOAD TABLE SYS.SOURCE$,產生 SYS_SOURCE$.txt、.sql、.ctl。-- 建表腳本 SYS_SOURCE$.sql
CREATE TABLE "SYS"."SOURCE$" ("OBJ#" NUMBER NOT NULL, "LINE" NUMBER NOT NULL, "SOURCE" VARCHAR2(4000));
-- SQL*Loader 控制檔 SYS_SOURCE$.ctl
LOAD DATA INFILE 'SYS_SOURCE$.txt' "STR X'0a'"
APPEND INTO TABLE "SYS"."SOURCE$"
FIELDS TERMINATED BY X'7c' TRAILING NULLCOLS
("OBJ#", "LINE", "SOURCE" CHAR(4000))
OWNER 為目標使用者,匯入目標 Schema。| 方法 | 適用條件 | 優點 | 缺點 | 成功率 |
|---|---|---|---|---|
| 閃回查詢 | UNDO 保留內、資料庫開啟、有權限 | 最簡單、無停機 | 受 UNDO_RETENTION 限制 | ★★★★★ |
| 基表歷史 | 同上,但視圖不可用或需繞過 | 直擊基表、精確 | 需知道精確時間點 | ★★★★☆ |
| ODU 工具 | 資料庫掛掉、UNDO 丟失、系統表損壞 | 不依賴資料庫實例、磁碟級恢復 | 複雜、需專業知識、耗時 | ★★★☆☆ |
DDL TRIGGER 記錄結構變更(CREATE OR REPLACE TRIGGER ... BEFORE DROP ON DATABASE)。UNDO_RETENTION(建議 ≥ 24 小時)並保證 UNDO 表空間足夠大。EXPDP METADATA_ONLY 備份結構定義。