恢复Truncate表的方法

很多人觉得把表truncate后,就无法恢复了,真的吗?

意外Truncate表的事情时有发生,ODU提供了方便的恢复Truncate表的功能。Truncate的表,只要原来的空间没有被重用(即数据被覆盖),则数据都是可以恢复的。(类似ODU的工具还有DUL、AUL等,大家可以研究一下,网络上都有安装包,但不管哪一种工具,都有它的弊端)

如果发现一个表被意外地Truncate,而需要马上恢复。首先要做的就是关闭数据库,或者OFFLINE那个表所在的表空间,或者关闭所有应用。目的只有一个,确保空间不会被重用,数据不会被覆盖。

下面举例说明如何用ODU恢复被Truncate掉的表。

1. 建立两个测试的表T1和T2,这两个表的数据完全一样。建两个数据完全一样的表的目的在于方便在恢复后对比数据。

SQL> connect test/test
已连接。

SQL> create table t1 as select * from dba_objects;

表已创建。

SQL> create table t2 as select * from t1;

表已创建。

SQL> truncate table t1;

表已截掉。

2. 我们OFFLINE掉T1表的表空间(实际上在实际的系统中,如果有比较多的活动,则表空间不容易被OFFLINE下来)。然后做一个Checkpoint,让ODU能够读到最新的数据字典数据。

SQL> select tablespace_name from user_tables where table_name='T1';

TABLESPACE_NAME
------------------------------
TEST

SQL> alter tablespace test offline;

表空间已更改。
SQL> alter system checkpoint;

系统已更改。

3. 运行ODU,并unload数据字典。

ODU> unload dict
get_bootstrap_dba: compat header size:12
CLUSTER C_USER# file_no: 1 block_no: 177
TABLE OBJ$ file_no: 1 block_no: 241
CLUSTER C_OBJ# file_no: 1 block_no: 49
CLUSTER C_OBJ# file_no: 1 block_no: 49
found IND$'s obj# 19
found IND$'s dataobj#:2,ts#:0,file#:1,block#:49,tab#:3
found TABPART$'s obj# 230
found TABPART$'s dataobj#:230,ts#:0,file#:1,block#:3313,tab#:0
found INDPART$'s obj# 234
found INDPART$'s dataobj#:234,ts#:0,file#:1,block#:3377,tab#:0
found TABSUBPART$'s obj# 240
found TABSUBPART$'s dataobj#:240,ts#:0,file#:1,block#:3473,tab#:0
found INDSUBPART$'s obj# 245
found INDSUBPART$'s dataobj#:245,ts#:0,file#:1,block#:3553,tab#:0
found IND$'s obj# 19
found IND$'s dataobj#:2,ts#:0,file#:1,block#:49,tab#:3
found LOB$'s obj# 156
found LOB$'s dataobj#:2,ts#:0,file#:1,block#:49,tab#:6
found LOBFRAG$'s obj# 258
found LOBFRAG$'s dataobj#:258,ts#:0,file#:1,block#:3761,tab#:0


4. 获取TEST用户下的T1表,也就是我们要恢复的表的信息:

ODU> desc test.t1

Object ID:33547
Storage(Obj#=33547 DataObj#=33549 TS#=11 File#=10 Block#=1400 Cluster=0)

NO. SEG INT Column Name                    Null?     Type
--- --- --- ------------------------------ --------- ------------------------------
  1   1   1 OWNER                                    VARCHAR2(30)
  2   2   2 OBJECT_NAME                              VARCHAR2(128)
  3   3   3 SUBOBJECT_NAME                           VARCHAR2(30)
  4   4   4 OBJECT_ID                                NUMBER
  5   5   5 DATA_OBJECT_ID                           NUMBER
  6   6   6 OBJECT_TYPE                              VARCHAR2(18)
  7   7   7 CREATED                                  DATE
  8   8   8 LAST_DDL_TIME                            DATE
  9   9   9 TIMESTAMP                                VARCHAR2(19)
 10  10  10 STATUS                                   VARCHAR2(7)
 11  11  11 TEMPORARY                                VARCHAR2(1)
 12  12  12 GENERATED                                VARCHAR2(1)
 13  13  13 SECONDARY                                VARCHAR2(1)

从上面的输出中,我们可以看到,TEST.T1表所在的表空间号为11,数据段头部为10号文件的1400号块。

5. 接下来用ODU扫描表空间的extent:

ODU> scan extent tablespace 11

scanning extent...
scanning extent finished.

6. 我们使用ODU来确定T1表原来的data object id。一般来说,数据段的数据块,一般是在段头后面相邻的块中。但是我们可以从段头来确认:

ODU> dump datafile 10 block 1400
Block Header:
block type=0x23 (ASSM segment header block)
block format=0x02 (oracle 8 or 9)
block rdba=0x02800578 (file#=10, block#=1400)
scn=0x0000.00286f2d, seq=4, tail=0x6f2d2304
block checksum value=0x0=0, flag=0
Data Segment Header:
  Extent Control Header
  -------------------------------------------------------------
  Extent Header:: extents: 1  blocks: 5
                  last map: 0x00000000  #maps: 0  offset: 668
      Highwater:: 0x02800579  (rfile#=10,block#=1401)
                  ext#: 0  blk#: 3   ext size:5
      #blocks in seg. hdr's freelists: 0
      #blocks below: 0
      mapblk: 0x00000000   offset: 0
  --------------------------------------------------------
  Low HighWater Mark :
      Highwater::  0x02800579  ext#: 0      blk#: 3      ext size: 5
  #blocks in seg. hdr's freelists: 0
  #blocks below: 0
  mapblk  0x00000000  offset: 0
  Level 1 BMB for High HWM block: 0x02800576
  Level 1 BMB for Low HWM block: 0x02800576
  --------------------------------------------------------
  Segment Type: 1 nl2: 1      blksz: 2048   fbsz: 0
  L2 Array start offset:  0x00000434
  First Level 3 BMB:  0x00000000
  L2 Hint for inserts:  0x02800577
  Last Level 1 BMB:  0x02800576
  Last Level 1I BMB:  0x02800577
  Last Level 1II BMB:  0x00000000
     Map Header:: next  0x00000000  #extents: 1    obj#: 33549  flag: 0x220000000
  Extent Map
  -------------------------------------------------------------
   0x02800576  length: 5

  Auxillary Map
  -------------------------------------------------------------
   Extent 0      :  L1 dba:  0x02800576 Data dba:  0x02800579
  -------------------------------------------------------------

   Second Level Bitmap block DBAs
  -------------------------------------------------------------
   DBA 1:   0x02800577

从上面的输出中的“Extent 0      :  L1 dba:  0×02800576 Data dba:  0×02800579”可以看到,段的第1个数据块的RDBA为0x02800579,也就是10号文件的1401块。

我们dump第10号文件的1401块头,来得到表T1原来的data object id:

ODU> dump datafile 10 block 1401 header
Block Header:
block type=0x06 (table/index/cluster segment data block)
block format=0x02 (oracle 8 or 9)
block rdba=0x02800579 (file#=10, block#=1401)
scn=0x0000.00285f2b, seq=2, tail=0x5f2b0602
block checksum value=0x0=0, flag=0
Data Block Header Dump:
 Object id on Block? Y
 seg/obj: 0x830b=33547  csc: 0x00.285f21  itc: 3  flg: E  typ: 1 (data)
     brn: 0  bdba: 0x2800576 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.00285f21
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
Data Block Dump:
================
flag=0x0 --------
ntab=1
nrow=16
frre=-1
fsbo=0x32
ffeo=0x145
avsp=0x113
tosp=0x113

可以看到,T1表原来的data object id就是33547

7. 使用ODU来unload数据:

ODU> unload table test.t1 object 33547

Unloading table: T1,object ID: 33547
Unloading segment,storage(Obj#=33547 DataObj#=33547 TS#=11 File#=10 Block#=1400 Cluster=0)

8. 使用sqlplus将TEST表空间ONLINE:

SQL> alter tablespace test online;

表空间已更改。

9. 使用sqlldr导入我们恢复的数据:

E:\ODU\data>sqlldr test/test control=TEST_T1.ctl

SQL*Loader: Release 9.2.0.8.0 - Production on 星期日 3月 15 15:13:56 2009

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

达到提交点,逻辑记录计数6502
达到提交点,逻辑记录计数13004
达到提交点,逻辑记录计数19506
达到提交点,逻辑记录计数26008
达到提交点,逻辑记录计数30071

至此,恢复数据的步骤已经完成。我们来对比一下数据,看看数据是否和被Truncate前的数据完全一样:

SQL> select * from t2 minus select * from t1;

未选定行

SQL> select * from t1 minus select * from t2;

未选定行

可以看到,数据已经完全恢复。

UPDATE :
从3.0.7版本开始,对truncate table的支持更方便。可能不用人工去找到原来的data object id,而支持使用:

unload table username.tablename object auto

ODU自动探测truncate之前的data object id,对分区表同样适用。

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31448824/viewspace-2136594/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/31448824/viewspace-2136594/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值