First Impression on BBED: recover deleted rows

Row Flag Structure

在看一个数据块的dump文件的时候,经常会发现类似如下的信息...

tl: 12 fb: --H-FL-- lb: 0x1 cc: 2


其中fb, lb, cc就是每一行数据头的信息,分别表示Row Flag, Lock Byte (ITL entry), Column Count. (tl, 应该表示每一行数据实际占用的空间大小,包括row header, 每一个column实际占用的字节数,和用来存储每个column长度的overhead。 tl的信息并没有实际存储。)

那么ROW Flag中的8个bit分别表示什么意思呢 (例如这里的H, F, L)?

---------------------------------------------------------------------------------------------------------------------

这8个bit从高到低依次是:

(128) : Cluster Key

(64) : Cluster Table Member

(32) : Header of row piece

(16): Deleted

(8) : First data piece

(4) : Last data piece

(2) : First column continues from previous piece

(1) : Last column continues in next piece

----------------------------------------------------------------------------------------------------------------------

因此,如果表中的一行记录完全处于一个block中(没有出现row chain, row migration), 不是属于聚簇表,也没有被删除,那么这一行数据的flag应该就是

32 (Header of row piece) + 8 (First data piece) + 4 (Last data piece) = 44 (0x2c), 这个也就是在dump文件中看到的标识--H-FL--

Recover Deleted Rows

那么恢复删除的数据跟上面提到的Row Flag有什么关系呢?注意到Row Flag中有一位是用来标示当前的行有没有被删除(Deleted),正常情况下这个bit是没有被set的,一旦当前行被删除了,这个bit就会被set了,而该行的数据并没有实际从block中擦除掉。因此一种很自然的想法就是,能不能通过简单地修改这个标识位,来恢复删除的数据呢? 答案自然是肯定的。
首先建立一个测试表,如下...
SQL> select * from test;

ID NAME
---------- ----------
1 Frank
2 Fraud

SQL
> alter system dump datafile 4 block 388;
查看dump文件可以看到这两条记录...
block_row_dump:
tab
0, row 0, @0x1f8c
tl:
12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 02
col
1: [ 5] 46 72 61 6e 6b
tab
0, row 1, @0x1f80
tl:
12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 03
col
1: [ 5] 46 72 61 75 64
如果现在删除第二行数据,再看看dump文件内容有什么变化...
SQL> delete from test where id = 2;

1 row deleted.

SQL
> commit;

Commit complete.

SQL
> alter system dump datafile 4 block 388;

System altered.
查看dump文件...
block_row_dump:
tab
0, row 0, @0x1f8c
tl:
12 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 02
col
1: [ 5] 46 72 61 6e 6b
tab
0, row 1, @0x1f80
tl:
2 fb: --HDFL-- lb: 0x2
end_of_block_dump
注意表中的第二行数据的标志位图信息由--H-FL--变成了--HDFL-- 第四个标志位被置成了D(deleted), 表示第二行数据被删除了。
数据被删除了,只是相应地更新了那一行的标志位,数据在block上还是存在的,可以通过bbed的输出来验证这一点...
BBED> set dba 4, 388
DBA
0x01000184 (16777604 4,388)

BBED
> p kdbr
sb2 kdbr[
0] @118 8076
sb2 kdbr[
1] @120 8064

BBED
> p *kdbr[1]
rowdata[
0]
----------
ub1 rowdata[
0] @8164 0x3c

BBED
> x /rnc
rowdata[
0] @8164
----------
flag
@8164: 0x3c (KDRHFL, KDRHFF, KDRHFD, KDRHFH)
lock
@8165: 0x02
cols
@8166: 0



BBED
> dump /v dba 4, 388 offset 8164
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
388 Offsets: 8164 to 8191 Dba:0x01000184
-------------------------------------------------------
3c020202 c1030546
72617564 2c000202 l <...�..Fraud,...
c1020546 72616e6b 01069bdb l �..Frank...

<
16 bytes per line>

BBED
>
从上面的输出可以看到第二行的标志位(值变成了0x3c)多了一个KDRHFD,表示这一行被删除了,但是从dump命令的输出可以看出数据(Fraud)还是存在的。只要这部分的数据没有被覆盖掉,应该可以通过修改数据行的标志位信息,把数据恢复回来的。
那么怎么去修改这个标志位呢,其实想想应该也不困难,只要找到标志位的offset, 通过modify命令将值从0x3c改回成0x2c就可以了。
从上面的examine命令的输出结果,可以得到第二行数据的标志位的offset为8164,那么改变这个值就不是难事了...
BBED> modify /x 2c offset 8164
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
388 Offsets: 8164 to 8191 Dba:0x01000184
------------------------------------------------------------------------
2c020202 c1030546
72617564 2c000202 c1020546 72616e6b 01069bdb

<
32 bytes per line>

BBED
> dump /v dba 4, 388 offset 8164
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
388 Offsets: 8164 to 8191 Dba:0x01000184
-------------------------------------------------------
2c020202 c1030546
72617564 2c000202 l ,...�..Fraud,...
c1020546 72616e6b 01069bdb l �..Frank...

<
16 bytes per line>

BBED
> p *kdbr[1]
rowdata[
0]
----------
ub1 rowdata[
0] @8164 0x2c

BBED
> x /r
rowdata[
0] @8164
----------
flag
@8164: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock
@8165: 0x02
cols
@8166: 2

col
0[2] @8167: 0xc1 0x03
col
1[5] @8170: 0x46 0x72 0x61 0x75 0x64


BBED
> x /rnc
rowdata[
0] @8164
----------
flag
@8164: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock
@8165: 0x02
cols
@8166: 2

col
0[2] @8167: 2
col
1[5] @8170: Fraud
从上面的输出可以看出,这条数据已经被“恢复”回来了。那么剩下要做的事情就是更新block的checksum, 
BBED> sum dba 4, 388 apply
Check value
for File 4, Block 388:
current
= 0x4fb9, required = 0x4fb9
现在通过SQL访问表TEST看看数据有没有被“恢复”回来...
SQL> alter system flush buffer_cache;

System altered.

SQL
> select * from test;

ID NAME
---------- ----------
1 Frank
2 Fraud

SQL
>
很显然,第二行数据被“恢复”回来了。
原文地址:https://www.cnblogs.com/fangwenyu/p/1958592.html