在生產系統上不小心修改了表數據后最快的方法是用閃回查詢找回。但時間不能超過undo_retention(默認90秒)。其實最標準的處理方法是在其他機器上將數據庫恢復到修改前的時刻。但數據庫比較大時恢復時間較長。真實場景可能比較急。那么也可以分析歸檔日志找回修改前的狀態。
分析歸檔日志的最常用方法是LOGMNR日志挖掘。但要求事先已經打開了附加日志RLOG_APPEND_LOGIC(默認不打開)。本文介紹另一種找回辦法dmlcvt
錄入測試數據
#登錄數據庫
[dmdba@node1 log]$ disql SYSDBA/SYSDBA
Server[LOCALHOST:5236]:mode is normal, state is open
login used time : 3.486(ms)
disql V8#創建測試表
SQL> create table test1(a varchar(100));
executed successfully
used time: 18.696(ms). Execute id is 500.#顯示當前事務號
SQL> select trx_id from v$sessions where sess_id=sessid;
LINEID TRX_ID
---------- --------------------
1 22079
used time: 1.073(ms). Execute id is 501.#插入數據
SQL> insert into test1 values('LIUQINGYAN');
affect rows 1
used time: 0.581(ms). Execute id is 502.
SQL> commit;
executed successfully
used time: 3.441(ms). Execute id is 503.#顯示當前事務號
SQL> select trx_id from v$sessions where sess_id=sessid;
LINEID TRX_ID
---------- --------------------
1 22080
used time: 0.241(ms). Execute id is 504.#修改表數據
SQL> update test1 set a='LIUQINGYAN1';
affect rows 1
used time: 1.161(ms). Execute id is 505.
SQL> commit;
executed successfully
used time: 3.493(ms). Execute id is 506.
#切歸檔
SQL> alter system switch logfile;
executed successfully
used time: 14.133(ms). Execute id is 0.
打開dmsql日志
2024-05-18 04:17:01.376 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:0 stmt:0x7f1d50035178 appname:disql ip:::1) [ORA]: select trx_id from v$sessions where sess_id=sessid;
2024-05-18 04:17:01.376 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:NULL appname:disql) TRX: START
2024-05-18 04:17:01.377 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:0x7f1d50035178 appname:disql ip:::1) [SEL] select trx_id from v$sessions where sess_id=sessid;
2024-05-18 04:17:01.377 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:0x7f1d50035178 appname:disql ip:::1) [SEL] select trx_id from v$sessions where sess_id=sessid; EXECTIME: 0(ms) ROWCOUNT: 1(rows).
2024-05-18 04:17:24.864 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:0x7f1d50035178 appname:disql ip:::1) [ORA]: insert into test1 values('LIUQINGYAN');
2024-05-18 04:17:24.864 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:0x7f1d50035178 appname:disql ip:::1) [INS] insert into test1 values('LIUQINGYAN');
2024-05-18 04:17:24.865 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:NULL appname:disql) trx[22079] alloc pseg page[0, 1311], page_lsn[55069], n_pages[1]
2024-05-18 04:17:24.865 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:0x7f1d50035178 appname:disql ip:::1) [INS] insert into test1 values('LIUQINGYAN'); EXECTIME: 0(ms) ROWCOUNT: 1(rows).
2024-05-18 04:17:27.457 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:0x7f1d50035178 appname:disql ip:::1) [ORA]: commit;
2024-05-18 04:17:27.457 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:0x7f1d50035178 appname:disql ip:::1) [DML] commit;
2024-05-18 04:17:27.457 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:NULL appname:disql) TRX: COMMIT
2024-05-18 04:17:27.457 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22079 stmt:NULL appname:disql) trx[22079]: pseg_page_free_for_insert_only_trx free pseg page (0, 1311), page_lsn = 55074
2024-05-18 04:17:27.460 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:0 stmt:NULL appname:disql) TRX: COMMIT LSN[55073]
2024-05-18 04:17:27.460 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:0 stmt:0x7f1d50035178 appname:disql ip:::1) [DML] commit; EXECTIME: 3(ms).
2024-05-18 04:17:32.464 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:0 stmt:0x7f1d50035178 appname:disql ip:::1) [ORA]: select trx_id from v$sessions where sess_id=sessid;
2024-05-18 04:17:32.464 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22080 stmt:NULL appname:disql) TRX: START
2024-05-18 04:17:32.464 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22080 stmt:0x7f1d50035178 appname:disql ip:::1) [SEL] select trx_id from v$sessions where sess_id=sessid; EXECTIME: 0(ms) ROWCOUNT: 1(rows).
2024-05-18 04:17:50.981 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22080 stmt:0x7f1d50035178 appname:disql ip:::1) [ORA]: update test1 set a='LIUQINGYAN1';
2024-05-18 04:17:50.981 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22080 stmt:0x7f1d50035178 appname:disql ip:::1) [UPD] update test1 set a='LIUQINGYAN1';
2024-05-18 04:17:50.982 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22080 stmt:NULL appname:disql) trx[22080] alloc pseg page[0, 1311], page_lsn[55083], n_pages[1]
2024-05-18 04:17:50.982 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22080 stmt:0x7f1d50035178 appname:disql ip:::1) [UPD] update test1 set a='LIUQINGYAN1'; EXECTIME: 0(ms) ROWCOUNT: 1(rows).
2024-05-18 04:17:52.612 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22080 stmt:0x7f1d50035178 appname:disql ip:::1) [ORA]: commit;
2024-05-18 04:17:52.612 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22080 stmt:0x7f1d50035178 appname:disql ip:::1) [DML] commit;
2024-05-18 04:17:52.612 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:22080 stmt:NULL appname:disql) TRX: COMMIT
2024-05-18 04:17:52.615 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:0 stmt:NULL appname:disql) TRX: COMMIT LSN[55086]
2024-05-18 04:17:52.615 (EP[0] sess:0x7f1d50011978 thrd:14617 user:SYSDBA trxid:0 stmt:0x7f1d50035178 appname:disql ip:::1) [DML] commit; EXECTIME: 3(ms).
update test1 set a='LIUQINGYAN'語句開啟了一個新事務,事務號:22080。系統為該事務在回滾段分配了1311號頁面用于保存前映像,以保證萬一rollback時可以回到事務開始前的狀態。
日志分析
dmlcvt F_TYPE=2 F_PATH=/home/dmdba/arch/ARCHIVE_LOCAL1_0x61299DA6_EP0_2024-05-18_01-49-37.log rec_level=2 rec_data=1 out_path=/home/dmdba/rec ts_id=1 file_id=0
#ts_id=1 回滾段表空間
#file_id=0 表空間內第0號文件
#out_path 日志分析結果目錄
日志分析節選如下:
#在ROLL.DBF文件為該事務分配1311號頁面
PAGE_INIT: (29, 1, 0, 1311)
WORD: (1, 0, 1311, 8, 2, 65535)
DWORD: (1, 0, 1311, 10, 4, 4294967295)
WORD: (1, 0, 1311, 14, 2, 65535)
DWORD: (1, 0, 1311, 16, 4, 4294967295)#1311號頁面用于保存22080事務的前映像(修改前的數據)
TRXID_H0: (1, 0, 1311, 36, 4, 22080)
BYTE: (1, 0, 1311, 42, 1, 0)
WORD: (1, 0, 1311, 43, 2, 55)
WORD: (1, 0, 1311, 45, 2, 55)
LINT64: (1, 0, 1311, 47, 8, 0)
PAGE_INIT: (36, 1, 0, 528)
WORD: (1, 0, 528, 8, 2, 65535)
DWORD: (1, 0, 528, 10, 4, 4294967295)
WORD: (1, 0, 528, 14, 2, 65535)
DWORD: (1, 0, 528, 16, 4, 4294967295)
WORD: (1, 0, 528, 36, 2, 248)
WORD: (1, 0, 528, 38, 2, 0)
BYTE: (1, 0, 528, 8153, 1, 0)
BYTE: (1, 0, 528, 8154, 1, 0)
BYTE: (1, 0, 528, 8155, 1, 0)
BYTE: (1, 0, 528, 8156, 1, 0)
BYTE: (1, 0, 528, 8157, 1, 0)
BYTE: (1, 0, 528, 8158, 1, 0)
BYTE: (1, 0, 528, 8162, 1, 0)
BYTE: (1, 0, 528, 8163, 1, 0)
BYTE: (1, 0, 528, 8164, 1, 0)
BYTE: (1, 0, 528, 8165, 1, 0)
BYTE: (1, 0, 528, 8166, 1, 0)
BYTE: (1, 0, 528, 8167, 1, 0)
BYTE: (1, 0, 528, 8168, 1, 0)
BYTE: (1, 0, 528, 8169, 1, 0)
BYTE: (1, 0, 528, 8170, 1, 0)
BYTE: (1, 0, 528, 8171, 1, 0)
BYTE: (1, 0, 528, 8172, 1, 0)
BYTE: (1, 0, 528, 8173, 1, 0)
BYTE: (1, 0, 528, 8174, 1, 0)
BYTE: (1, 0, 528, 8175, 1, 0)
BYTE: (1, 0, 528, 8176, 1, 0)
BYTE: (1, 0, 528, 8177, 1, 0)
BYTE: (1, 0, 528, 8178, 1, 0)
BYTE: (1, 0, 528, 8179, 1, 0)
BYTE: (1, 0, 528, 8180, 1, 0)
BYTE: (1, 0, 528, 8181, 1, 0)
BYTE: (1, 0, 528, 8182, 1, 0)
BYTE: (1, 0, 528, 8183, 1, 0)
BYTE: (1, 0, 528, 8153, 1, 128)
WORD: (1, 0, 528, 38, 2, 1)
ANY: (1, 0, 528, 40, 32, 0x40560000000000001F0500000000000000000000000000000000000000000000)
ANY: (1, 0, 1311, 55, 64, 0x40000203040000003F560000000000000000000026040000FFFFFFFFFFFFFFFF7FFFFF0100000000000000010000000A004C495551494E4759414E0000003700)#上一個事務(22079)寫入的0x426表的數據:LIUQINGYANUREC_UPD: (seq:4, nrec_tid:22079, tabid:0x426(), rowid:1, n_keys:0)(id:0, 0x4C495551494E4759414E, [LIUQINGYAN])
WORD: (1, 0, 1311, 45, 2, 119)pkg_ver=1, pkg_type=0, use_hash=0, n_ep=1, dsc_seqno=0, db_magic=1630117286, p_db_magic=0, term_id=0, prev_term_id=0, c_seqno=10012, c_lsn=55084, l_seqno=10013, g_seqno=10013, prev_lsn=55084
min_lsn=55085, max_lsn=55086, pkg_len=512, data_off=256, real_file_off=196608, n_dps=0, n_pll=1, use_hash=0
BYTE: (1, 0, 1311, 42, 1, 1)
ANY: (1, 0, 1311, 119, 37, 0x25001202060000004056000000000000640000000000008002000000260400006800447700)#22080事務描述結束UREC_TRX_END: (seq:6, trxid:22080)
由上可見:
事務號(TRXID)22080
分配(PAGE_INIT)回滾頁面? 1311
22080事務修改前的數據:22079事務寫入的‘LIUQINGYAN’。與dmsql日志中吻合。
注:tabid:0x426是表的十六進制對象號,轉換成十進制是1062。
下面我們讀一下ROLL.DBF文件
由上可見回滾文件中確實存在LIUQINGYAN。將1311號頁面dd出來也可以找到LIUQINGYAN,而其他頁面不存在。與日志分析結果吻合。
繼續測試
錄入數據
#更新數據
SQL> update test1 set a='LIUQINGTAO';
affect rows 1
used time: 6.593(ms). Execute id is 500.
SQL> commit;
executed successfully
used time: 3.684(ms). Execute id is 501.
SQL> alter system switch logfile;
executed successfully
#切歸檔
SQL> alter system switch logfile;
executed successfully
used time: 14.133(ms). Execute id is 0.
查看dmlog日志
2024-05-18 05:37:44.797 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:0 stmt:0x7fa81c035178 appname:disql ip:::1) [ORA]: update test1 set a='LIUQINGTAO';
2024-05-18 05:37:44.798 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:26091 stmt:NULL appname:disql) TRX: START
2024-05-18 05:37:44.799 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:26091 stmt:0x7fa81c035178 appname:disql ip:::1) [UPD] update test1 set a='LIUQINGTAO';
2024-05-18 05:37:44.800 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:26091 stmt:NULL appname:disql) trx[26091] alloc pseg page[0, 1311], page_lsn[59648], n_pages[1]
2024-05-18 05:37:44.801 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:26091 stmt:0x7fa81c035178 appname:disql ip:::1) [UPD] update test1 set a='LIUQINGTAO'; EXECTIME: 1(ms) ROWCOUNT: 1(rows).
2024-05-18 05:37:46.554 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:26091 stmt:0x7fa81c035178 appname:disql ip:::1) [ORA]: commit;
2024-05-18 05:37:46.554 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:26091 stmt:0x7fa81c035178 appname:disql ip:::1) [DML] commit;
2024-05-18 05:37:46.554 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:26091 stmt:NULL appname:disql) TRX: COMMIT
2024-05-18 05:37:46.557 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:0 stmt:NULL appname:disql) TRX: COMMIT LSN[59651]
2024-05-18 05:37:46.557 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:0 stmt:0x7fa81c035178 appname:disql ip:::1) [DML] commit; EXECTIME: 3(ms).
:38:59.187 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:0 stmt:0x7fa81c035178 appname:disql ip:::1) [ORA]: alter system switch logfile;
2024-05-18 05:39:13.932 (EP[0] sess:0x7fa81c011978 thrd:19497 user:SYSDBA trxid:0 stmt:NULL appname:disql) FREE SESSION
2024-05-18 05:39:16.743 (EP[0] sess:NULL thrd:NULL user:NULL trxid:NULL stmt:NULL) trx[26091]: purg2_page free pseg page (0, 1311), page_lsn = 59682
update test1 set a='LIUQINGTAO'語句開啟了一個新事務,事務號:26091。值得注意的是系統為該事務重用了1311號回滾頁面用于保存前映像
日志分析
dmlcvt F_TYPE=2 F_PATH=/home/dmdba/arch/ARCHIVE_LOCAL1_0x61299DA6_EP0_2024-05-18_05-37-19.log rec_level=2 rec_data=1 out_path=/home/dmdba/rec ts_id=1 file_id=0
日志分析結果
PAGE_INIT: (29, 1, 0, 1311)
WORD: (1, 0, 1311, 8, 2, 65535)
DWORD: (1, 0, 1311, 10, 4, 4294967295)
WORD: (1, 0, 1311, 14, 2, 65535)
DWORD: (1, 0, 1311, 16, 4, 4294967295)
TRXID_H0: (1, 0, 1311, 36, 4, 26091)
BYTE: (1, 0, 1311, 42, 1, 0)
WORD: (1, 0, 1311, 43, 2, 55)
WORD: (1, 0, 1311, 45, 2, 55)
LINT64: (1, 0, 1311, 47, 8, 0)
PAGE_INIT: (36, 1, 0, 528)
WORD: (1, 0, 528, 8, 2, 65535)
DWORD: (1, 0, 528, 10, 4, 4294967295)
WORD: (1, 0, 528, 14, 2, 65535)
DWORD: (1, 0, 528, 16, 4, 4294967295)
WORD: (1, 0, 528, 36, 2, 248)
WORD: (1, 0, 528, 38, 2, 0)
BYTE: (1, 0, 528, 8153, 1, 0)
BYTE: (1, 0, 528, 8154, 1, 0)
BYTE: (1, 0, 528, 8155, 1, 0)
BYTE: (1, 0, 528, 8156, 1, 0)
BYTE: (1, 0, 528, 8157, 1, 0)
BYTE: (1, 0, 528, 8158, 1, 0)
BYTE: (1, 0, 528, 8159, 1, 0)
BYTE: (1, 0, 528, 8160, 1, 0)
BYTE: (1, 0, 528, 8161, 1, 0)
BYTE: (1, 0, 528, 8162, 1, 0)
BYTE: (1, 0, 528, 8163, 1, 0)
BYTE: (1, 0, 528, 8164, 1, 0)
BYTE: (1, 0, 528, 8165, 1, 0)
BYTE: (1, 0, 528, 8180, 1, 0)
BYTE: (1, 0, 528, 8181, 1, 0)
BYTE: (1, 0, 528, 8182, 1, 0)
BYTE: (1, 0, 528, 8183, 1, 0)
BYTE: (1, 0, 528, 8153, 1, 128)
WORD: (1, 0, 528, 38, 2, 1)
ANY: (1, 0, 528, 40, 32, 0xEB650000000000001F0500000000000000000000000000000000000000000000)
ANY: (1, 0, 1311, 55, 65, 0x410002030300000040560000000000000000000026040000FFFFFFFF001F05000037000100000000000000010000000B004C495551494E4759414E310000003700)UREC_UPD: (seq:3, nrec_tid:22080, tabid:0x426(), rowid:1, n_keys:0)(id:0, 0x4C495551494E4759414E31, [LIUQINGYAN1])
WORD: (1, 0, 1311, 45, 2, 120)pkg_ver=1, pkg_type=0, use_hash=0, n_ep=1, dsc_seqno=0, db_magic=1630117286, p_db_magic=0, term_id=0, prev_term_id=0, c_seqno=11622, c_lsn=59649, l_seqno=11623, g_seqno=11623, prev_lsn=59649
min_lsn=59650, max_lsn=59651, pkg_len=512, data_off=256, real_file_off=162816, n_dps=0, n_pll=1, use_hash=0
BYTE: (1, 0, 1311, 42, 1, 1)
ANY: (1, 0, 1311, 120, 37, 0x2500120205000000EB65000000000000000000000000000000000000000000000000007800)UREC_TRX_END: (seq:5, trxid:26091)
由上可見:
事務號(TRXID)26091
分配(PAGE_INIT)回滾頁面? 1311
26091事務修改前的數據:22080事務寫入的‘LIUQINGYAN1’。與dmsql日志中吻合。
既然是重用1311頁面,那么上一份數據肯定被覆蓋了。
下面檢查得到了驗證
回滾文件里記錄的數據變成了LIUQINGYAN1