oracle_恢复Truncate表数据

标签:
itoracleddl |
1.原理
首先,我们分析一下TRUNCATE的过程。TRUNCATE不会逐个清除用户数据块上的数据,而仅仅重置数据字典和元数据块上的元数据(如存储段头和扩 展段图)。也就是说,此时,其基本数据并未被破坏,而是被系统回收、等待被重新分配————因此,要恢复被TRUNCATE的数据,需要及时备份其所在的 数据文件。
然后,再分析一下表扫描的过程(我曾经在这篇文章中分析了小表扫描的过程:oracle逻辑IO的秘密: Full Table Scan: Part 1):Oracle 会读取段头的元数据,获得高水位线等信息,然后读取高水位线以下被格式化的数据块。因此,理论上讲,如果能够将被重置的元数据和元数据块重新构造出来,就 能使数据能被重新读取。然而,要完成这个任务,难度相当大————要找出原有的所有元数据块被保证其每个字节与被TRUANCATE之前完全相同———— 看起来似乎是一个不可能完成的任务。
不过,我们可以换一角度来找方法————如果我们已经有一套元数据及数据块,然后将被TRUNCATE的用户数据块的内容取代其用户数据块的内容,是否可以“骗”过Oracle,让它读出这些数据呢?
回顾一下表扫描的过程,这个方法应该是可行的。我们只要想办法构造出一个结构相同、且具有完整元数据信息和格式化了的用户数据块的傀儡表对象,然后将被 TRUNCATE的用户数据块找出,再将其数据内容部分嫁接到傀儡对象的用户数据块,使Oracle以外这是傀儡对象的数据,就能让Oracle扫描并读 出数据内容。其原理用图示描述如下:
http://s11/mw690/8317516bxd2c1aa74c08a&690
2.PL/SQL代码实现
HELLODBA.COM>insert into demo.truntab select * from
demo.t_objects;
47585 rows
created.
HELLODBA.COM>commit;
Commit
complete.
HELLODBA.COM>select count(*) from
demo.truntab;
COUNT(*)
----------
47585
HELLODBA.COM>truncate table
demo.truntab;
Table
truncated.
HELLODBA.COM>declare
2 tgtowner
varchar2(30);
3 tgttable
varchar2(30);
4 datapath
varchar2(4000);
5 datadir
varchar2(30);
6 rects
varchar2(30);
7 recfile
varchar2(30);
8 rstts
varchar2(30);
9 rstfile
varchar2(30);
10 blksz
number;
11 rectab
varchar2(30);
12 rsttab
varchar2(30);
13 copyfile
varchar2(30);
14 begin
15 tgtowner
:= 'DEMO';
16 tgttable
:= 'TRUNTAB';
17 datapath
:= 'D:\oracle\product\10.2.0\oradata\EDGAR\DATAFILE\';
18 datadir :=
'FY_DATA_DIR';
19
Fy_Recover_data.prepare_files(tgtowner, tgttable, datapath,
datadir, rects, recfile, rstts, rstfile,
blksz);
20
首先,我们分析一下TRUNCATE的过程。TRUNCATE不会逐个清除用户数据块上的数据,而仅仅重置数据字典和元数据块上的元数据(如存储段头和扩 展段图)。也就是说,此时,其基本数据并未被破坏,而是被系统回收、等待被重新分配————因此,要恢复被TRUNCATE的数据,需要及时备份其所在的 数据文件。
然后,再分析一下表扫描的过程(我曾经在这篇文章中分析了小表扫描的过程:oracle逻辑IO的秘密: Full Table Scan: Part 1):Oracle 会读取段头的元数据,获得高水位线等信息,然后读取高水位线以下被格式化的数据块。因此,理论上讲,如果能够将被重置的元数据和元数据块重新构造出来,就 能使数据能被重新读取。然而,要完成这个任务,难度相当大————要找出原有的所有元数据块被保证其每个字节与被TRUANCATE之前完全相同———— 看起来似乎是一个不可能完成的任务。
不过,我们可以换一角度来找方法————如果我们已经有一套元数据及数据块,然后将被TRUNCATE的用户数据块的内容取代其用户数据块的内容,是否可以“骗”过Oracle,让它读出这些数据呢?
回顾一下表扫描的过程,这个方法应该是可行的。我们只要想办法构造出一个结构相同、且具有完整元数据信息和格式化了的用户数据块的傀儡表对象,然后将被 TRUNCATE的用户数据块找出,再将其数据内容部分嫁接到傀儡对象的用户数据块,使Oracle以外这是傀儡对象的数据,就能让Oracle扫描并读 出数据内容。其原理用图示描述如下:
http://s11/mw690/8317516bxd2c1aa74c08a&690
2.PL/SQL代码实现