恢復delete 的rows Whenrows are deleted in Oracle the data is not actually removed. The row is simplymarked as deleted and the free space counters and pointers adjustedaccordingly. The status of a row is stored in the Row Header which occupies thefirst few bytes of each row. 當row 被delete 的時候,實際上data 並沒有被remove,只是將該row 標記爲delete,然後其對應的空間被統計爲free space。 row 的status 存在每個row的row header裏。 TheRow Header consists of the Row Flag, Lock Byte (ITL entry) and Column Count.The first of these - the Row Flag - is a single byte that holds a bitmask thatshows the status of the row. The bitmask is decoded as follows: 我們dump 一個block,看一個row Flag,來幫助理解這個bitmask。 SYS@dave2(db2)> alter system dump datafile1 block 115362; System altered. SYS@dave2(db2)> oradebug setmypid Statement processed. SYS@dave2(db2)> oradebug tracefile_name /u01/app/oracle/admin/dave2/udump/dave2_ora_9396.trc trace file有關row的信息如下: block_row_dump: tab 0, row 0, @0x1f90 tl: 16 fb: --H-FL--lb: 0x1 cc: 1 --在這裏fb代表Row Flag,lb代表Lock Byte ,cc代表column Count.
--此時Row Flag = 32+8+4=44 即16進制的2c. col 0: [12] 44 4d 4d 20 20 69 73 2044 42 41 21 tab 0, row 1, @0x1f7b tl: 21 fb: --H-FL-- lb: 0x2 cc: 1 col 0: [17] 64 6d 6d 65 20 6c 69 6b65 20 4f 72 61 63 6c 65 21 end_of_block_dump 我們的表dvd裏只有2行記錄,所以這裏顯示的row 爲2. 注意這裏的fb: --H-FL--。 其有8個選項,每個值分別與bitmask 對應。 Therefore,columns that fit within a single block, are not chained, migrated or part of aclustered table and are not deleted will have the following attributes: (1)Head of Row Piece (2)First Data Piece (3)Last Data Piece 如果一個row 沒有被刪除,那麼它就具有上面的3個屬性,即Flag 表示爲:--H-FL--. 這裏的字母分別代表屬性的首字母。其對應的值:32 + 8 + 4 =44 or 0x2c. 如果一個row 被delete了,那麼row flag 就會更新,bitmask 裏的deleted 被設置爲16. 此時row flag 爲: 32 + 16 + 8 + 4 = 60 or 0x3c. 驗證一下: SYS@dave2(db2)> delete from dvd whererownum=1; 1 row deleted. SYS@dave2(db2)> commit; Commit complete. 查看dump 的標記: block_row_dump: tab 0, row 0, @0x1f90 tl: 2 fb: --HDFL--lb: 0x1 tab 0, row 1, @0x1f7b tl: 21 fb: --H-FL-- lb: 0x0 cc: 1 col 0: [17] 64 6d 6d 65 20 6c 69 6b65 20 4f 72 61 63 6c 65 21 end_of_block_dump 這裏的row 1flag 變成了--HDFL--。 現在我們用bbed 將刪除的row 1 內容找回來。 BBED> set dba1,115362 offset 0 DBA 0x0041c2a2(4309666 1,115362) OFFSET 0 BBED> find /c DMM File: /u01/app/oracle/oradata/dave2/system01.dbf(1) Block: 115362 Offsets: 8176 to 8191 Dba:0x0041c2a2 ------------------------------------------------------------------------ 444d4d20 20697320 44424121 020616b3 <32 bytes per line> BBED> d /v dba 1,115362 offset 8176 count 128 File:/u01/app/oracle/oradata/dave2/system01.dbf (1) Block: 115362 Offsets: 8176 to 8191 Dba:0x0041c2a2 ------------------------------------------------------- 444d4d20 20697320 44424121 020616b3 l DMM is DBA!...3 <16 bytes per line> 注意:我們還是可以通過dump查看我們delete 掉的row記錄。但是在sql裏用select 已經看出到了。 這個也證明,delete 並未真正的刪除data。 我們的row 的內容保存在offset 8176的位置,我們將offset 往前移動一段,再dump,來確定row header的內容。 這個移位有一定的規律。 我們看一下: BBED> d /v dba 1,115362 offset 8176 count 128 File: /u01/app/oracle/oradata/dave2/system01.dbf(1) Block: 115362 Offsets: 8176 to 8191 Dba:0x0041c2a2 ------------------------------------------------------- 444d4d20 20697320 44424121 020616b3 l DMM is DBA!...3 我們的一條記錄是從444d4d20開始的,此時的offsets8176開始的。我們offset 減小一位,在dump: BBED> d /v dba 1,115362 offset 8175 File:/u01/app/oracle/oradata/dave2/system01.dbf (1) Block: 115362 Offsets: 8175 to 8191 Dba:0x0041c2a2 ------------------------------------------------------- 0c444d4d 20206973 20444241 210206d7 l.DMM is DBA!..× 73 l s <16 bytes per line> 此時dump 的內容多了2個字符,而一個完整的是8個字符,所以要想完整的顯示,一次要減少4個offsets。 BBED> d /v dba 1,115362 offset 8172 File:/u01/app/oracle/oradata/dave2/system01.dbf (1) Block: 115362 Offsets: 8172 to 8191 Dba:0x0041c2a2 ------------------------------------------------------- 3c01010c 444d4d20 20697320 44424121 l <...DMM is DBA! 0206d773 l ..×s <16 bytes per line> 這裏已經出現了我們3c(deleted)標誌,但是注意這裏的位置的根據我們的查找的字符串來分的,實際在block裏的分割方式不一樣按照我們的offset 來進行。
我們可以通過row directory 來進行一個確認。 我們print row directory 確認一下: BBED> p kdbr sb2 kdbr[0] @110 8080 sb2 kdbr[1] @112 8059 BBED> p *kdbr[0] rowdata[21] ----------- ub1 rowdata[21] @8172 0x3c BBED> p *kdbr[1] rowdata[0] ---------- ub1 rowdata[0] @8151 0x2c 通過row directory,我們可以確認對應row記錄的row header保存在offset 8172的位置,值爲3c。 我們find 字符串的目的就是爲了和row directory 中的offset 進行比較。
他們相近時,就可以確定。 現在我們將@8172位置的3c 變成2c。 即從deleted 變成正常。 BBED> modify /x 2c offset 8172 File:/u01/app/oracle/oradata/dave2/system01.dbf (1) Block: 115362 Offsets: 8172 to 8191 Dba:0x0041c2a2 ------------------------------------------------------------------------ 2c01010c 444d4d20 20697320 44424121 0206d773 <32 bytes per line> BBED> sum apply Check value for File 1, Block 115362: current = 0x2cb4, required = 0x2cb4 --flush buffer cache,然後查詢 SYS@dave2(db2)> alter system flushbuffer_cache; System altered. SYS@dave2(db2)> select * from dvd; JOB -------------------------------------------------------------------------------- DMM is DBA! Dave like Oracle! 之前delete 的數據已經恢復出來。