impdp加上table_exists_action=replace覆蓋數據后的恢復方法


案例背景:

2020年5月的一天,某客戶將數據庫中的業務核心用戶NC65導入數據庫中。不幸的是事情就注定要發生,導入的目標數據庫是當前運行的生產數據庫,並且在impdp導入時,添加了table_exists_action=replace選項(此選項時到impdp導入對象時,如發現對象已經存在,就會先刪除對象,再創建對象)。來了,不幸的事情發生了,生產環境的NC65用戶數據被還原到備份時的狀態,最近幾天新產生的數據被清空,慘了,要被領導批了。此生產環境中數據庫還無rman備份、在導入前也沒有做expdp備份,不幸的事情真是這么相似。但幸運的是數據庫運行在歸檔模式,並且有完整的最近7天的歸檔日志。此時可以在歸檔日志上面動動手腳,利用歸檔日志來手動前滾數據庫。 恢復思路

1,利用歸檔日志手動前滾

數據庫可以利用歸檔日志前滾,此時我們只能利用歸檔日志手動前滾。logminer是Oracle官方推出的用於分析日志的腳本,可以將日志中的DML操作解析成SQL語句,是否真如大家想的這樣呢?肯定不是的,此時問題來了,Oracle日志中不會記錄對象的名字,只記錄對象的id號,並且此環境中impdp在導入時已經重建相關對象,所以對象id號碼已經發生了變化,此時給logminer添加了不少困難。logmnr分析結果如下圖

SQL> select table_name,count(*) from V$LOGMNR_CONTENTS group by table_name;

TABLE_NAME                         COUNT(*)
-------------------------------- ----------
                                       6457
OBJ# 292119                           20385
OBJ# 292109                           71354
OBJ# 292117                           55421
STATS_TARGET$                           140
WRI$_OPTSTAT_IND_HISTORY                 68
CDEF$                                    44
OBJ# 292112                          143545
OBJ# 292124                           85876
WRI$_ADV_OBJECTS                         12
OBJ# 292116                           26929
OBJ# 292123                           85876
SEQ$                                      2
SEG$                                   2587
TAB$                                    139
WRI$_OPTSTAT_HISTHEAD_HISTORY          2442
OBJ# 292121                          112601
WRI$_SEGADV_OBJLIST                       6
HIST_HEAD$                             1221
MON_MODS_ALL$                            46
DBMS_TABCOMP_TEMP_CMP                    12
SDO_GEOR_DDL_$$                    12
WRI$_ADV_FINDINGS                         6
DEFERRED_STG$                             6
OBJ# 292122                          112601
CCOL$                                    44
WRI$_ADV_MESSAGE_GROUPS                  12
OBJ# 292118                           55421
WRI$_OPTSTAT_HISTGRM_HISTORY           7143
OBJ$                                     35
CON$                                     66
WRI$_ADV_ACTIONS                         12
WRI$_ADV_REC_ACTIONS                      6
OBJ# 292120                           20385
WRI$_OPTSTAT_TAB_HISTORY                 47
DBMS_TABCOMP_TEMP_UNCMP                  12
IND$                                     72
HISTGRM$                              14371
COL$                                   1224
LOB$                                      4
WRI$_ADV_RECOMMENDATIONS                 12
OBJ# 292115                           26929

logminer解析出來的SQL語句如下: sql_redo大致如下,不僅對象名無法解析,字段名,字段類型均無法解析,所以sql_redo顯示的時候只能使用COL1,COL2這樣去顯示字段名,使用HEXTORAW()實際存儲值去顯示字段值。

insert into "UNKNOWN"."OBJ# 292120"("COL 1","COL 2","COL 3","COL 4","COL 5","COL
 6","COL 7","COL 8","COL 9","COL 10","COL 11","COL 12","COL 13","COL 14","COL 15
","COL 16","COL 17","COL 18","COL 19","COL 20","COL 21","COL 22","COL 23","COL 2
4","COL 25","COL 26","COL 27","COL 28","COL 29","COL 30","COL 31","COL 32","COL
33","COL 34","COL 35","COL 36","COL 37","COL 38","COL 39","COL 40","COL 41","COL
 42","COL 43","COL 44","COL 45","COL 46","COL 47","COL 48","COL 49","COL 50","CO
L 51","COL 52","COL 53","COL 54","COL 55","COL 56","COL 57","COL 58","COL 59","C
OL 60","COL 61","COL 62","COL 63","COL 64","COL 65","COL 66","COL 67","COL 68","
COL 69","COL 70","COL 71","COL 72","COL 73","COL 74","COL 75","COL 76","COL 77",
"COL 78","COL 79","COL 80","COL 81","COL 82") values (HEXTORAW('d3a6b8b6c6b1bedd
bde1cbe3b7bdcabdb6d4d3a6d2f8d0d0d5cbbba7'),HEXTORAW('303035474756'),NULL,NULL,NU
LL,HEXTORAW('c102'),HEXTORAW('80'),HEXTORAW('c102'),HEXTORAW('c102'),NULL,NULL,N
ULL,NULL,NULL,NULL,HEXTORAW('4e'),NULL,HEXTORAW('3e1166'),HEXTORAW('c102'),NULL,
HEXTORAW('3232303131303031433131303030303030303036344a42523130303143313130303030
3030303036344c3841313030314331313030303030303030354e30344f31'),NULL,NULL,HEXTORA
W('c102'),HEXTORAW('b9f3d6ddb8bbb4efbae3c9ccc3b3d3d0cfdeb9abcbbe'),NULL,HEXTORAW
('3e1166'),HEXTORAW('313030314331313030303030303030354e30344f'),HEXTORAW('313030
314331313030303030303030354d5a5549'),HEXTORAW('313030314331313030303030303030385
a545741'),HEXTORAW('3130303143313130303030303030303634443159'),HEXTORAW('3130303
143313130303030303030303634455947'),HEXTORAW('46332d4378782d3031'),HEXTORAW('7e'
),HEXTORAW('7e'),NULL,HEXTORAW('313030325a303130303030303030303030314b31'),HEXTO
RAW('31303031433131303030303030303030324a3357'),HEXTORAW('3030303143313130303030
30303030303041364d'),NULL,NULL,NULL,NULL,NULL,NULL,HEXTORAW('3130303143313130303
...

2,重構數據字典

需要讓logminer工具能正常解析對象,那么第一步就是需要恢復數據字典的內容,此時只能手動重構logminer字典信息,然后通過構造的字典信息去解析歸檔日志,得到正確的sql_redo。 那么如何去構造logminer字典信息呢?首先介紹一下logminer字典的來源。 通過dbms_logmnr_d.build去創建一個字典文件,對字典文件分析發現字典的數據來源為

OBJ$ 
TAB$
COL$
TS$
IND$
USER$
TABPART$
INDPART$
TABSUBPART$
TABCOMPART$
TYPE$
COLTYPE$
ATTRIBUTE$
LOB$
CDEF$
CCOL$
ICOL$
ATTRCOL$
NTAB$
OPQTYPE$
SUBCOLTYPE$
KOPM$
PROPS$
REFCON$
PARTOBJ$

那么我們只需要把數據字典基表數據還原到impdp誤操作之前即可正確解析出sql_redo,這里采用的是方法是新建一個用戶TEST,然后將生產用戶NC65的8號dmp文件導入到TEST里,由於表結構這些與生產用戶完全一樣, 那么我們就可以利用這個新建用戶去構造出刪除之前的對象元數據信息。只需要OBJ$,COL$,TAB$,LOB$信息無誤,就能解析出正確的sql_redo。構造大致過程如下:

2.1 分析出刪除之前的表的OBJ#

方法最簡單的是通過閃回查詢,很不幸的是我們使用閃回查詢時ORA-01555了,通過logminer去分析impdp時刻的歸檔日志,對OBJ$進行分析,則可以找到NC65的所有對象刪除前的OBJ$信息,並保存在表OBJ_NC65里 創建表OBJ_NC65用於保留impdp誤操作前NC65的表的OBJ$信息:

create table OBJ_NC65 as select * from obj$ where 1=2;

delete的sql_undo為insert,將下面sql查詢出來的sql插入到OBJ_NC65表中:
 select SQL_UNDO from V$LOGMNR_CONTENTS 
  where table_name='OBJ$' 
    and sql_redo like 'delete from%' 
        and sql_redo like '%'||'"TYPE#" = ''2'''||'%' 
        and sql_redo not like '%'||'"DATAOBJ#" IS NULL'||'%'
        and sql_redo like '%'||'"OWNER#" = ''92'''||'%' ;

2.2.owner#=97為TEST,首先通過表名關聯,找到obj#對應關系

create table t as select b.obj# obj_old,b.name,a.obj# obj_new,a.owner# from obj$ a,obj_nc65 b where a.name=b.name and a.owner#=97;

2.3.更新新建用戶TEST的元數據信息,構造出能夠正確解析的logminer字典信息

update obj$ a set obj#=(select obj_old from t where t.obj_new=a.obj#) where obj# in (select obj_new from t);
update col$ a set obj#=(select obj_old from t where t.obj_new=a.obj#) where obj# in (select obj_new from t);
update lob$ a set obj#=(select obj_old from t where t.obj_new=a.obj#) where obj# in (select obj_new from t);
update tab$ a set obj#=(select obj_old from t where t.obj_new=a.obj#) where obj# in (select obj_new from t);

2.4.刷新shared pool

alter system flush shared_pool;

2.5.解析歸檔

找出歸檔開始解析,只保留commit成功的記錄,並把輸出保存在表logmnr_new中,這里注意,如果需要分析的歸檔過多,建議分批次去做分析。否則會出現ORA-04030。 sqlplus "/as sysdba" << EOF

exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10131_1012773265.dbf',sys.dbms_logmnr.new);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10132_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10133_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10134_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10135_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10136_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10137_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10138_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10139_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10140_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10141_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10142_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10143_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10144_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10145_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10146_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10147_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10148_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10149_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10150_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10151_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10152_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10153_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.add_logfile('/u02/ncgdlog/1_10154_1012773265.dbf',sys.dbms_logmnr.addfile);
exec sys.dbms_logmnr.start_logmnr(options=>dbms_logmnr.dict_from_online_catalog+dbms_logmnr.committed_data_only);
create table logmnr_new tablespace users as select * from v\$logmnr_contents;
execute dbms_logmnr.end_logmnr;
quit;
EOF

2.6.刪除TEST用戶,並重建TEST,並導入NC65 8號的dmp。

3 開始還原數據

編寫腳本按事務提交時間在TEST用戶下去依次執行sql進行恢復。

4,案例總結

1,生產環境一定要有RMAN的備份。

2,X86環境一定要搭建一個容災環境,哪怕是用普通的PC服務器也一定要有一個ADG容災環境。

3,IMPDP導入時,切記不要在生產環境操作。

4,IMPDP只是作為數據遷移和數據備份與還原的工具,並不是數據庫備份與還原工具。

5,如果真出現問題,不會操作不要慌,聯系我們公司專家,千萬不要2次破壞。

*************************************作者介紹*****************************************

原創作者:認真就輸

聯系電話:18081072613 微信、QQ:18081072613

轉載就注明出處

*************************************************************************************


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM