[20220909]bbed关于删除记录恢复的问题.txt

–//快下班被别人问的关于删除记录使用bbed恢复的问题,我开始以为很快讲解完,删除记录oracle仅仅打上一个标识,实际的记录还存在.
–//实际上地方问的是多次DML(删除记录的情况),实际上只要dump还能看到,bbed还是可以恢复的,做一个例子说明:

1.环境:
SCOTT@test01p> @ver1
PORT_STRING VERSION BANNER CON_ID
——————– ———- —————————————————————————- ——
IBMPC/WIN_NT64-9.1.0 12.2.0.1.0 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 – 64bit Production 0

SCOTT@test01p> create table deptx as select * from dept ;
Table created.

SCOTT@test01p> select rowid from deptx where rownum=1;
ROWID
——————
AAAHGVAALAAAACjAAA

SCOTT@test01p> @ rowid AAAHGVAALAAAACjAAA
OBJECT FILE BLOCK ROW ROWID_DBA DBA TEXT
———- ———- ———- ———- ———– —— —————————————-
29077 11 163 0 0x2C000A3 11,163 alter system dump datafile 11 block 163

SCOTT@test01p> alter system checkpoint ;
System altered.

SCOTT@test01p> alter system checkpoint ;
System altered.

2.测试:
BBED> set dba 11,164
DBA 0x02c000a4 (46137508 11,164)
–//注:bbed for windows 访问的block要加1,主要问题在于无法识别数据文件的第0块(OS块头)

BBED> p *kdbr
rowdata[66]
———–
ub1 rowdata[66] @8162 0x2c

BBED> p kdbr
sb2 kdbr[0] @142 8038
sb2 kdbr[1] @144 8016
sb2 kdbr[2] @146 7996
sb2 kdbr[3] @148 7972

SCOTT@test01p> delete from deptx where deptno=20;
1 row deleted.

SCOTT@test01p> commit ;
Commit complete.

SCOTT@test01p> alter system checkpoint ;
System altered.

–//通过bbed观察如下:
BBED> p kdbr dba 11,164
sb2 kdbr[0] @142 8038
sb2 kdbr[1] @144 8016
sb2 kdbr[2] @146 7996
sb2 kdbr[3] @148 7972

BBED> x /rncc *kdbr[0]
rowdata[66] @8162
———–
flag@8162: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8163: 0x00
cols@8164: 3
col 0[2] @8165: 10
col 1[10] @8168: ACCOUNTING
col 2[8] @8179: NEW YORK

BBED> x /rncc *kdbr[1]
rowdata[44] @8140
———–
flag@8140: 0x3c (KDRHFL, KDRHFF, KDRHFD, KDRHFH)
lock@8141: 0x02
cols@8142: 0
–//你可以发现flag 从0x2c变成 0x3c,打上了KDRHFD标识表示删除,恢复实际上就是修改flag=0x2c(也就是取消KDRHFD标识).
–//继续:

SCOTT@test01p> delete from deptx where deptno=30;
1 row deleted.

SCOTT@test01p> commit ;
Commit complete.

SCOTT@test01p> alter system checkpoint ;
System altered.

BBED> p kdbr dba 11,164
sb2 kdbr[0] @142 8038
sb2 kdbr[1] @144 8016
sb2 kdbr[2] @146 7996
sb2 kdbr[3] @148 7972
–//偏移量还是不变,也就是这样的情况下以上两条记录都可以恢复.

SCOTT@test01p> update deptx set dname=upper(dname) where deptno=10;
1 row updated.

SCOTT@test01p> commit ;
Commit complete.

SCOTT@test01p> alter system checkpoint ;
System altered.

BBED> p kdbr dba 11,164
sb2 kdbr[0] @142 8038
sb2 kdbr[1] @144 8016
sb2 kdbr[2] @146 7996
sb2 kdbr[3] @148 7972
–//我执行update操作,但是行目录并没有修改,主要原因在于DML修改的记录长度没有变化,oracle并不会改变行目录的偏移。
–//而是就地修改相关记录信息。

SCOTT@test01p> update deptx set dname=upper(dname)||’0′ where deptno=10;
1 row updated.

SCOTT@test01p> commit ;
Commit complete.

SCOTT@test01p> alter system checkpoint ;
System altered.

BBED> p kdbr dba 11,164
sb2 kdbr[0] @142 7945
sb2 kdbr[1] @144 2
sb2 kdbr[2] @146 -1
sb2 kdbr[3] @148 7972
–//在DML后修改记录长度发生变化后,oracle在修改kdbr[0]的偏移时,同时也修改kdbr[1],kdbr[2]的信息,
–//这个应该是oracle的一个设计理念,顺手把以前没做的事情做完…
–//你可以从修改的信息可以推断,如果下次操作是插入,使用那个行目录时应该从kdbr[1],kdbr[2]选择。
–//如果你仔细观察可以发现删除记录的行目录记录的偏移记录的信息形成1个链表结构,sb2 kdbr[2] = -1 表示链表结构的尾部.
–//并且可以通过行目录偏移 kdbr[N] 是否 >= kdbh.kdbhnrow (当前为4),来确定是否指向正确的记录信息。

BBED> p kdbh dba 11,164
struct kdbh, 14 bytes @124
ub1 kdbhflag @124 0x00 (NONE)
b1 kdbhntab @125 1
b2 kdbhnrow @126 4
=======================================================
sb2 kdbhfrre @128 1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sb2 kdbhfsbo @130 26
sb2 kdbhfseo @132 7945
b2 kdbhavsp @134 7987
b2 kdbhtosp @136 7987

–//kdbhfrre = 1 ,表示链表结构的开头,也就是如果在块DML有插入时,会先使用kdbr[1]行目录.
–//你可以发现这时kdbr[1],kdbr[2]执行的偏移并没有覆盖,要恢复一定ok的.

BBED> assign kdbr[1] = 8016;
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y
sb2 kdbr[0] @144 8016

BBED> assign kdbr[2] = 7996;
sb2 kdbr[0] @146 7996

BBED> x /rncc *kdbr[1]
rowdata[71] @8140
———–
flag@8140: 0x3c (KDRHFL, KDRHFF, KDRHFD, KDRHFH)
lock@8141: 0x02
cols@8142: 0

BBED> x /rncc *kdbr[2]
rowdata[51] @8120
———–
flag@8120: 0x3c (KDRHFL, KDRHFF, KDRHFD, KDRHFH)
lock@8121: 0x03
cols@8122: 0

–//修改flag取消KDRHFD标识:
BBED> assign offset 8140 = 0x2c;
ub1 rowdata[0] @8140 0x2c

BBED> assign offset 8120 = 0x2c;
ub1 rowdata[0] @8120 0x2c

BBED> x /2rncc *kdbr[2]
rowdata[51] @8120
———–
flag@8120: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8121: 0x03
cols@8122: 3

col 0[2] @8123: 30
col 1[5] @8126: SALES
col 2[7] @8132: CHICAGO

rowdata[71] @8140
———–
flag@8140: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8141: 0x02
cols@8142: 3

col 0[2] @8143: 20
col 1[8] @8146: RESEARCH
col 2[6] @8155: DALLAS
–//现在2条记录都可以显见,剩下就是恢复对应数据块的完整性以及一致性问题.

BBED> sum apply
Check value for File 11, Block 164:
current = 0x9fe2, required = 0x9fe2

BBED> verify
DBVERIFY – Verification starting
FILE = D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF
BLOCK = 163

Block Checking: DBA = 46137507, Block Type = KTB-managed data block
data header at 0x2c4027c
kdbchk: row locked by non-existent transaction
table=0 slot=2
lockid=3 ktbbhitc=3
Block 163 failed with check code 6101

–//lock 偏移8121 =0x0.
BBED> assign offset 8121=0x0;
ub1 rowdata[0] @8121 0x00

BBED> sum apply
Check value for File 11, Block 164:
current = 0x9ce2, required = 0x9ce2

BBED> verify
DBVERIFY – Verification starting
FILE = D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF
BLOCK = 163

Block Checking: DBA = 46137507, Block Type = KTB-managed data block
data header at 0x2c4027c
kdbchk: entries on the free list are not ordered
next=8016 nrow=4 chas=1
Block 163 failed with check code 6106

BBED> assign kdbh.kdbhfrre=-1
sb2 kdbhfrre @128 -1

BBED> sum apply
Check value for File 11, Block 164:
current = 0x631c, required = 0x631c

BBED> verify
DBVERIFY – Verification starting
FILE = D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF
BLOCK = 163

Block Checking: DBA = 46137507, Block Type = KTB-managed data block
data header at 0x2c4027c
kdbchk: xaction header lock count mismatch
trans=2 ilk=1 nlo=2
Block 163 failed with check code 6108

–//lock 偏移8141 =0x0.
BBED> assign offset 8141=0x0;
ub1 rowdata[0] @8141 0x00

BBED> sum apply
Check value for File 11, Block 164:
current = 0x611c, required = 0x611c

BBED> verify
DBVERIFY – Verification starting
FILE = D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF
BLOCK = 163

Block Checking: DBA = 46137507, Block Type = KTB-managed data block
data header at 0x2c4027c
kdbchk: the amount of space used is not equal to block size
used=119 fsc=0 avsp=7987 dtl=8064
Block 163 failed with check code 6110

–//dtl-used-fsc = avsp
–//8064-119-0 = 7945

BBED> assign kdbh.kdbhavsp=7945;
b2 kdbhavsp @134 7945

BBED> sum apply
Check value for File 11, Block 164:
current = 0x6126, required = 0x6126

BBED> verify
DBVERIFY – Verification starting
FILE = D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF
BLOCK = 163

Block Checking: DBA = 46137507, Block Type = KTB-managed data block
data header at 0x2c4027c
kdbchk: space available on commit is incorrect
tosp=7987 fsc=0 stb=0 avsp=7945
Block 163 failed with check code 6111

BBED> assign kdbh.kdbhtosp=7945;
b2 kdbhtosp @136 7945

BBED> sum apply
Check value for File 11, Block 164:
current = 0x611c, required = 0x611c

BBED> verify
DBVERIFY – Verification starting
FILE = D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF
BLOCK = 163
–//OK现在恢复完成.

SCOTT@test01p> alter system flush BUFFER_CACHE;
System altered.

SCOTT@test01p> select * from deptx;
DEPTNO DNAME LOC
———- ——————– ————-
10 ACCOUNTING0 NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
–//删除记录已经恢复.
–//原来deptno= 10 的记录没有覆盖,理论将也可以恢复.继续尝试看看.

BBED> assign kdbr[0]=8038
sb2 kdbr[0] @142 8038

BBED> x /rncc *kdbr[0]
rowdata[93] @8162
———–
flag@8162: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8163: 0x00
cols@8164: 3

col 0[2] @8165: 10
col 1[10] @8168: ACCOUNTING
col 2[8] @8179: NEW YORK
–//这样修改行目录偏移指向执行原来的位置.

BBED> sum apply
Check value for File 11, Block 164:
current = 0x6173, required = 0x6173

BBED> verify
DBVERIFY – Verification starting
FILE = D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF
BLOCK = 163

Block Checking: DBA = 46137507, Block Type = KTB-managed data block
data header at 0x2c4027c
kdbchk: xaction header lock count mismatch
trans=2 ilk=1 nlo=0
Block 163 failed with check code 6108

BBED> assign offset 8163 = 0x02
ub1 rowdata[0] @8163 0x02

BBED> sum apply
Check value for File 11, Block 164:
current = 0x6373, required = 0x6373

BBED> verify
DBVERIFY – Verification starting
FILE = D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF
BLOCK = 163

Block Checking: DBA = 46137507, Block Type = KTB-managed data block
data header at 0x2c4027c
kdbchk: the amount of space used is not equal to block size
used=118 fsc=0 avsp=7945 dtl=8064
Block 163 failed with check code 6110

–//dtl-used-fsc = avsp
–//8064-118-0 = 7946

BBED> assign kdbh.kdbhavsp=7946;
b2 kdbhavsp @134 7946

BBED> assign kdbh.kdbhtosp=7946;
b2 kdbhtosp @136 7946

BBED> sum apply
Check value for File 11, Block 164:
current = 0x6373, required = 0x6373

BBED> verify
DBVERIFY – Verification starting
FILE = D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF
BLOCK = 163
–//ok,现在恢复到原始建立时的状态.

SCOTT@test01p> alter system flush BUFFER_CACHE;
System altered.

SCOTT@test01p> select * from deptx;
DEPTNO DNAME LOC
———- ——————– ————-
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON

3.总结:
–//很久不使用bbed,有点生疏了。
–//我前面的恢复定位行目录信息时使用原来显示的信息,实际的恢复只能通过find检索0x2c,0x3c字符定位。
–//然后通过执行 x /rncc offset NNNN,确定显示的信息是否正确。获得NNNN偏移是绝对偏移,必须减去kdbh的偏移(这里是124,前面
–//有3个ITL槽),这样才能确定行目录的相对偏移值。
–//总之到对应的数据块操作相对复杂!!!

BBED> p kdbr dba 11,164
sb2 kdbr[0] @142 8038
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sb2 kdbr[1] @144 8016
sb2 kdbr[2] @146 7996
sb2 kdbr[3] @148 7972

BBED> p kdbh dba 11,164
struct kdbh, 14 bytes @124
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ub1 kdbhflag @124 0x00 (NONE)
b1 kdbhntab @125 1
b2 kdbhnrow @126 4
sb2 kdbhfrre @128 1
sb2 kdbhfsbo @130 26
sb2 kdbhfseo @132 7945
b2 kdbhavsp @134 7987
b2 kdbhtosp @136 7987

BBED> x /rncc *kdbr[0]
rowdata[66] @8162
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
———–
flag@8162: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8163: 0x00
cols@8164: 3
col 0[2] @8165: 10
col 1[10] @8168: ACCOUNTING
col 2[8] @8179: NEW YORK
–// 8162-124 = 8038