1.环境说明
OS:Centos7.9
DB:Oracle Database 12c Enterprise Edition Release 12.2.0.1.0
2.实验步骤
简单说明:当我们在delete一行数据时,实际该行数据并没有删除,而是给该行打了一个删除标记,只要未被覆盖即可通过修改删除标记找回该行数据。
1.创建测试表,插入几行数据(提交并刷盘)
2.使用BBED观察此时数据块的信息
3.使用delete删除一行数据(提交并刷盘)
4.使用BBED与之前数据进行比较
5.修复delete数据,完成恢复实验
3.创建测试表
--为了能使实验看的清晰明了,我们创建一个新的表空间
SYS@EVA>create tablespace tbs2 datafile '/u01/app/oracle/oradata/EVA/tbs2.dbf' size 10m;
Tablespace created.
--修改scott用户默认表空间
SYS@EVA>alter user scott default tablespace tbs2;
User altered.
--创建测试表
SCOTT@EVA>create table tb1 (id int,name varchar2(5));
Table created.
--插入两行数据
SCOTT@EVA>insert into tb1 values(1,'AAAAA');
1 row created.
SCOTT@EVA>insert into tb1 values(2,'BBBBB');
1 row created.
--提交并刷盘
SCOTT@EVA>commit;
Commit complete.
SCOTT@EVA>alter system flush buffer_cache;
System altered.
SCOTT@EVA>select * from tb1;
ID NAME
---------- ------------------------------
1 AAAAA
2 BBBBB
4.使用BBED查看数据删除前的块内容
--查询表中数据位于哪个文件几号块
SCOTT@EVA>select distinct dbms_rowid.rowid_relative_fno(rowid) file#,dbms_rowid.rowid_block_number(rowid) block# from tb1;
FILE# BLOCK#
---------- ----------
6 134
SCOTT@EVA>select FILE#,TS#,NAME from v$datafile where file#=6;
FILE# TS# NAME
---------- ---------- ------------------------------
6 6 /u01/app/oracle/oradata/EVA/tbs2.dbf
--使用BBED查看数据
[oracle@oracledb ~]$ bbed password=blockedit listfile=/home/oracle/tbs2.list blocksize=8192 mode=edit
BBED> info
File# Name Size(blks)
----- ---- ----------
1 /u01/app/oracle/oradata/EVA/tbs2.dbf 1281
BBED> set file 1 block 134
FILE# 1
BLOCK# 134
BBED> map
File: /u01/app/oracle/oradata/EVA/tbs2.dbf (1)
Block: 134 Dba:0x00400086
------------------------------------------------------------
KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes @0
struct ktbbh, 72 bytes @20
struct kdbh, 14 bytes @100
struct kdbt[1], 4 bytes @114
sb2 kdbr[2] @118
ub1 freespace[8042] @122
ub1 rowdata[24] @8164
ub4 tailchk @8188
BBED> p kdbr --查看行数据存放offset
sb2 kdbr[0] @118 8076
sb2 kdbr[1] @120 8064
BBED> p *kdbr[0] --查看第一行数据实际存放offset 8176
rowdata[12]
-----------
ub1 rowdata[12] @8176 0x2c
BBED> p *kdbr[1] --查看第二行数据实际存放offset 8164
rowdata[0]
----------
ub1 rowdata[0] @8164 0x2c
--由于数据块结构是块头从前往后写,数据从后往前写,中间为空闲区域,因此我们设置从offset8000开始
BBED> set offset 8000 count 8192
BBED> d
File: /u01/app/oracle/oradata/EVA/tbs2.dbf (1)
Block: 134 Offsets: 8000 to 8191 Dba:0x00400086
------------------------------------------------------------------------
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 2c010202 c1030542 42424242 2c010202 c1020541 41414141 01065e70 --尾部四个字节为尾部校验
解释:2c010202 c1020541 41414141 =>
2c表示行状态,01表示lock,02表示2个字段,02表示第一个字段有2个字节,c102表示十进制的1,05表示第二个字段有5个字节,5个41表示大写的A
2c010202 c1030542 42424242 =>
2c表示行状态,01表示lock,02表示2个字段,02表示第一个字段有2个字节,c103表示十进制的2,05表示第二个字段有5个字节,5个42表示大写的B
--使用dump函数转换
SCOTT@EVA>select dump(1,16) from dual; SCOTT@EVA>select dump('AAAAA',16) from dual;
DUMP(1,16) DUMP('AAAAA',16)
----------------- --------------------
Typ=2 Len=2: c1,2 Typ=96 Len=5: 41,41,41,41,41
SCOTT@EVA>select dump(2,16) from dual; SCOTT@EVA>select dump('BBBBB',16) from dual;
DUMP(2,16) DUMP('BBBBB',16)
----------------- --------------------
Typ=2 Len=2: c1,3 Typ=96 Len=5: 42,42,42,42,42
--从下面显示也可以看出先插入的数据在offset8176,后插入的数据在offset8164,由此可见数据是由后往前存储的
BBED> set offset 8176
OFFSET 8176
BBED> x /rncccccc --r读取,n数字类型,c字符类型
rowdata[12] @8176
-----------
flag@8176: 0x2c (KDRHFL, KDRHFF, KDRHFH) --记住此处的flag
lock@8177: 0x01
cols@8178: 2
col 0[2] @8179: 1
col 1[5] @8182: AAAAA
BBED> set offset 8164
OFFSET 8164
BBED> x /rncccccc
rowdata[0] @8164
----------
flag@8164: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8165: 0x01
cols@8166: 2
col 0[2] @8167: 2
col 1[5] @8170: BBBBB
5.使用delete删除一行数据
--删除一行数据
SCOTT@EVA>delete tb1 where id=1;
1 row deleted.
--提价
SCOTT@EVA>commit;
Commit complete.
--脏数据刷盘
SCOTT@EVA>alter system flush buffer_cache;
System altered.
--查询数据,ID为1的数据已被删除
SCOTT@EVA>select * from tb1;
ID NAME
---------- ------------------------------------------------------------
2 BBBBB
6.使用BBED查看数据删除后的块内容
BBED> set file 1 block 134 offset 8000 count 8192
FILE# 1
BLOCK# 134
OFFSET 8000
COUNT 8192
BBED> d
File: /u01/app/oracle/oradata/EVA/tbs2.dbf (1)
Block: 134 Offsets: 8000 to 8191 Dba:0x00400086
------------------------------------------------------------------------
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 2c000202 c1030542 42424242 3c020202 c1020541 41414141 02067479
此时我们跟之前的数据对比发现,只有第一行数据的2c变成了3c,其他都没有改变
BBED> set offset 8176
OFFSET 8176
BBED> x /rncccccccc
rowdata[12] @8176
-----------
flag@8176: 0x3c (KDRHFL, KDRHFF, KDRHFD, KDRHFH) --此处也可以看出flag变为了3c
lock@8177: 0x02
cols@8178: 0
7.使用BBED修复删除的数据
BBED> set offset 8176
OFFSET 8176
BBED> d
File: /u01/app/oracle/oradata/EVA/tbs2.dbf (1)
Block: 134 Offsets: 8176 to 8191 Dba:0x00400086
------------------------------------------------------------------------
3c020202 c1020541 41414141 02067479
BBED> m /x 2c
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y
File: /u01/app/oracle/oradata/EVA/tbs2.dbf (1)
Block: 134 Offsets: 8176 to 8191 Dba:0x00400086
------------------------------------------------------------------------
2c020202 c1020541 41414141 02067479
BBED> sum apply
BBED> set offset 8000
OFFSET 8000
BBED> d
File: /u01/app/oracle/oradata/EVA/tbs2.dbf (1)
Block: 134 Offsets: 8000 to 8191 Dba:0x00400086
------------------------------------------------------------------------
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 2c000202 c1030542 42424242 2c020202 c1020541 41414141 02067479
--清空缓存
SCOTT@EVA>alter system flush buffer_cache;
System altered.
--查询数据已恢复
SCOTT@EVA>select * from tb1;
ID NAME
---------- ------------------------------------------------------------
1 AAAAA
2 BBBBB
至此,数据恢复完成!
实际生产环境中,在没有任何备份没有开启归档的情况下,当我们误删除了某行数据并且redo已被覆盖,我们可以尝试用此种方法进行恢复!