oracle truncate 原理,对于Truncate的一点点理解和实验

无数次事故告诉我们,Truncate是一项很危险的动作。一不小心搞错,就会带来毁灭性的打击。我们都知道当Truncate命令发起之后,Oracle实际上并没有在删除底层数据块上的数据,而是要等到重用的时候才会把这一部分数据回收,于是这给了我们一个能够恢复数据库的机会。

对于Truncate单表来说,其实就相当于摧毁我们的一个段,我们数据库中的物理结构是由段区块三个构成的。首先我们要最需要了解的就是一张“图谱”?图谱是什么?就是一个段的组成结构,而最能表现段的构成的就是一个三级位图块的结构图。我们可以看到一个段最先是由段头块构成的,段头其实就是第1个L3块,只有当这些无法记录下的时候,才会产生第2个L3级块,不过这种情况非常少见,段头块指向了若干的L2位图块,每个L2位图块又指向了若干L1位图块,L1位图块则指向了真正的数据块。

1.建立实验环境所需要的表

SQL> create tablespace a1 datafile '/oracle/app/oracle/oradata/ora11/a1.dbf' size 20m;

Tablespace created.

SQL> create user a1 identified by a1 default tablespace a1;

User created.

SQL> grant dba to a1;

Grant succeeded.

SQL> connect a1/a1

Connected.

SQL> create table a as select * from dba_tables;

Table created.

实验环境建立完成之后,我们就需要摸清楚我们的这个段A的位图及数据块分布情况,我们不直接从视图里面查,这里我们考虑需要通过bbed的方式从数据块中获取位图及数据块分布情况。

2.段头块/L3位图块指向了哪些L2位图块

段由哪些区间构成?这个信息我们需要从段头块中获取出来。当你创建一个段后,即使你没有往里面插入任何数据,系统也是会预先分配一些区给你的。所以段头块是那个块,我们可以通过dba_segments查询出来。就算truncate了这个段,我们仍然能够从dba_segments中查询到段头的信息。

SQL> select HEADER_FILE,HEADER_BLOCK from dba_segments where SEGMENT_NAME='A' and owner='A1';

HEADER_FILE HEADER_BLOCK

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

5          130

找到了段头块,我们就可以用bbed挖掘下信息。

BBED> set filename '/oracle/app/oracle/oradata/ora11/a1.dbf'

FILENAME        /oracle/app/oracle/oradata/ora11/a1.dbf

BBED> set block 130

BLOCK#          130

BBED> dump /v offset 0 count 20

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets:    0 to   19  Dba:0x00000000

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

23a20000 82004001 d8321400 00000104 l #.@.....

848d0000                            l ....

这里我们可以看到段头块的第一个offset是23。那么我们的段头块指向的L2位图块在offset 5192的位置。这里请记住段头块的标示是23。

BBED> dump /v offset 5192 count 100

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets: 5192 to 5291  Dba:0x00000000

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

81004001 00000000 00000000 00000000 l ..@.............

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000                            l ....

从这里我们既可以找到我们的L2位图块,81004001,这里只有1个L2块,因为后面都是00000000(空),因为涉及到操作系统字节序的问题,这里需要转换换成01400081。转换后我们可以使用下列查询找到文件号和块号。

SQL> select dbms_utility.data_block_address_file(to_number('01400081','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('01400081','xxxxxxxx')) as blockno from dual;

FILENO    BLOCKNO

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

5        129

3.L2位图块指向了哪些L1位图块

接下来我们可以继续读我们的L2位图块来寻找我们的L1位图块。可以看到L2的第一个offset是21。请记住L2位图块的标示是21。

BBED> set block 129

BLOCK#          129

BBED> dump /v offset 0 count 20

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 129     Offsets:    0 to   19  Dba:0x00000000

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

21a20000 81004001 d4321400 00000604 l !.@.....

48a10000                            l H

L2指向L1数据块的位置从offset 116开始。到哪儿结束需要看后面有没有00000000(空)

BBED> dump /v offset 116 count 100

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 129     Offsets:  116 to  215  Dba:0x00000000

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

80004001 01000100 90004001 01000100 l ..@.......@.....

a0004001 01000100 b0004001 01000100 l ........

c0004001 01000100 d0004001 01000100 l ........

e0004001 05000100 00000000 00000000 l ............

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000                            l ....

从dump出来的地方我们来看,前面是一个地址,后面跟着是01000100,比较规律,大概7组之后就变成00000000(空)了。 跟上面一样因为字节序的问题,这里我们需要将80004001转换成01400080。然后我们通过下列查询得到了区块的位置。而后面的01000100,前面的01则这个L1下面的块全部填满,无空数据块,后面的01则代表这个块是instance 1产生的。而最后的一个05000100,05则代表着这个L1下面还有空块,可以插入。而后面的01我们说过代表着是instance。如果这个系统是个rac的系统,节点2也插入了数据,那么这里就会显示05000200。

SQL> select dbms_utility.data_block_address_file(to_number('01400080','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('01400080','xxxxxxxx')) as blockno from dual

union

select dbms_utility.data_block_address_file(to_number('01400090','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('01400090','xxxxxxxx')) as blockno from dual

union

select dbms_utility.data_block_address_file(to_number('014000a0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000a0','xxxxxxxx')) as blockno from dual

union

select dbms_utility.data_block_address_file(to_number('014000b0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000b0','xxxxxxxx')) as blockno from dual

union

select dbms_utility.data_block_address_file(to_number('014000c0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000c0','xxxxxxxx')) as blockno from dual

union

select dbms_utility.data_block_address_file(to_number('014000d0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000d0','xxxxxxxx')) as blockno from dual

union

select dbms_utility.data_block_address_file(to_number('014000e0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000e0','xxxxxxxx')) as blockno from dual;

FILENO    BLOCKNO

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

5        128

5        144

5        160

5        176

5        192

5        208

5        224

7 rows selected.

通过上述查询,我们找到了7个L1块的信息。

4.L1位图块指向了哪些数据块

前面我们查到了我们的L2块上指向的L1块,并且清楚的知道哪个L1下面是满的,哪个L1下面还有空闲块。我们就从拿最后一个有空闲块的L1位图块进行分析。

BBED> set block 224

BLOCK#          224

BBED> dump /v offset 0 count 10

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 224     Offsets:    0 to    9  Dba:0x00000000

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

20a20000 e0004001 d432              l  .@.

可以看到L1的第一个offset是20。请记住L1位图块的标示是20。L1指向数据块的位置从offset 204开始。到哪儿结束需要看后面有没有00000000(空)

BBED> dump /v offset 204 count 80

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 224     Offsets:  204 to  283  Dba:0x00000000

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

e0004001 08000000 00000000 e8004001 l ........

08000000 08000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

大家可以看到这里的值是e0004001,08000000,00000000,下一组值是e8004001,08000000,08000000,然后面就是00000000(空)。

这两个的意思是告诉我们L1指向数据块的起始位置,比如e0004001,就是文件5,块224,也就是它自己本身。08000000就代表着这个块后面的连续7个块都是的。而e8004001,08000000,08000000,就是文件5,块232,08000000就代表着这个块后面的连续7个块也是的。而最后一个08000000则代表着offset,这里我们可以不用去管它。所以这里我们就能够知道我们的L1块下面具体的数据块有:224(它本身),225,226,227,228,229,230,231,232,233,234,235,236,237,238,239。我们来用下列语句查证一下。

SQL> select distinct dbms_rowid.rowid_block_number(rowid) from a order by 1

................ ................ ................ ................ ................

220

221

222

223

225

226

227

228

229

230

231

232

233

可以看到223后面直接就是225,直接此处跳空,这是因为我们的224是L1位图块,后面紧跟着我们刚刚说的225,226,227,228,229,230,231,232,233。但是问题是,这里看不到后面的234到239?这是因为234到239还是空闲没有格式化过的块,但是它已经被L1锁定了。那么我们的L1能不能看到这些情况呢?我们可以观察offset 396。

BBED> dump /v offset 396 count 50

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 224     Offsets:  396 to  445  Dba:0x00000000

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

11111111 11000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

0000                                l ..

这里可以看到的是11111111,11000000。那么这个代表什么意思呢?如果这个块是full的话,就是1,是unformatted的话就是0,正好和我们前面看到的吻合。

Truncate如何恢复?

1.Data Object ID恢复

前面我们介绍了我们的段的组成形式,这里来总结一下,首先是段头块,它指向了L2块,L2块指向了L1块,而L1块则指向了我们真实的物理数据块。试着想想,如果我们发起truncate之后,Oracle会怎么做?

SQL> select OBJECT_NAME,OBJECT_ID,DATA_OBJECT_ID from dba_objects where OBJECT_NAME='A';

OBJECT_NAME                     OBJECT_ID DATA_OBJECT_ID

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

A                                   75722          75722

我们先来看一下对象,当我们创建对象的之后,OBJECT_ID和data_object_id都会是一样的,但是当我们发生truncate之后,我们的object_id不会变,而data_object_id则会变掉。

SQL> truncate table a;

Table truncated.

SQL> select OBJECT_NAME,OBJECT_ID,DATA_OBJECT_ID from dba_objects where OBJECT_NAME='A';

OBJECT_NAME                     OBJECT_ID DATA_OBJECT_ID

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

A                                   75722          75727

这里可以看到我们Truncate表之后,data_object_id从75722变成了75727。我们分别看一下我们的段头块,L2位图块,L1位图块,数据块,这个ID是否有变化。分别从检查块130,129,224,225

BBED> set block 130

BLOCK#          130

BBED> dump /v offset 272 count 20

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets:  272 to  291  Dba:0x00000000

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

cf270100 00000010 80004001 08000000 l ......@.....

00000000                            l .....

BBED> set block 129

BLOCK#          129

BBED> dump /v offset 104 count 20

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 129     Offsets:  104 to  123  Dba:0x00000000

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

cf270100 01000000 00000000 80004001 l ..........@.

05000100                            l ....

BBED> set block 128

BLOCK#          128

BBED>  dump /v offset 192 count 10

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 128     Offsets:  192 to  201  Dba:0x00000000

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

cf270100 e6151400 0000              l ..

BBED> set block 144

BLOCK#          144

BBED> dump /v offset 192 count 10

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 144     Offsets:  192 to  201  Dba:0x00000000

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

ca270100 de300f00 0000              l ..

BBED> set block 160

BLOCK#          160

BBED> dump /v offset 192 count 10

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 160     Offsets:  192 to  201  Dba:0x00000000

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

ca270100 de300f00 0000              l ..

BBED> set block 176

BLOCK#          176

BBED> dump /v offset 192 count 10

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 176     Offsets:  192 to  201  Dba:0x00000000

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

ca270100 de300f00 0000              l ..

BBED> set block 192

BLOCK#          192

BBED> dump /v offset 192 count 10

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 192     Offsets:  192 to  201  Dba:0x00000000

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

ca270100 de300f00 0000              l ..

BBED> set block 208

BLOCK#          208

BBED> dump /v offset 192 count 10

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 208     Offsets:  192 to  201  Dba:0x00000000

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

ca270100 de300f00 0000              l ..

BBED> set block 224

BLOCK#          224

BBED> dump /v offset 192 count 10

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 224     Offsets:  192 to  201  Dba:0x00000000

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

ca270100 de300f00 0000              l ..

BBED> set block 225

BLOCK#          225

BBED> dump /v offset 24 count 10

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 225     Offsets:   24 to   33  Dba:0x00000000

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

ca270100 90121400 0000              l ......

通过对各个块的dump,发现段头和L2位图块的data_obj_id已经发生了改变,从ca270100变成了cf270100,而只有第一个L1发生了变化,数据块则没有发生改变。

那我们是不是把data_obj_id修改回来就能够恢复数据呢?

BBED> set block 130

BLOCK#          130

BBED> modify /x ca offset 272

Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130              Offsets:  272 to  291           Dba:0x00000000

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

ca270100 00000010 80004001 08000000 00000000

BBED> set block 129

BLOCK#          129

BBED> modify /x ca offset 104

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 129              Offsets:  104 to  123           Dba:0x00000000

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

ca270100 01000000 00000000 80004001 05000100

BBED> set block 128

BLOCK#          128

BBED> modify /x ca offset 192

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 128              Offsets:  192 to  211           Dba:0x00000000

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

ca270100 e6151400 00000000 80004001 08000000

BBED> sum apply

Check value for File 0, Block 128:

current = 0x35a9, required = 0x35a9

这里还需要修改数据字典,否则会报错。

SQL> select * from a1.a;

select * from a1.a

*

ERROR at line 1:

ORA-08103: object no longer exists

SQL> update OBJ$ set DATAOBJ#= 75722 where OBJ#= 75722;

1 row updated.

SQL> commit;

Commit complete.

SQL> update TAB$ set DATAOBJ#=75722 where OBJ#=75722;

1 row updated.

SQL> commit;

Commit complete.

SQL> update  SEG$ set HWMINCR=75722 where FILE#=5 and BLOCK#=130;

1 row updated.

SQL> commit;

Commit complete.

SQL> shutdown immediate;

Database closed.

Database dismounted.

ORACLE instance shut down.

SQL> startup

ORACLE instance started.

Total System Global Area  839282688 bytes

Fixed Size                  2233000 bytes

Variable Size             511708504 bytes

Database Buffers          322961408 bytes

Redo Buffers                2379776 bytes

Database mounted.

Database opened.

SQL> select * from a1.a;

no rows selected

2.段头高水位信息恢复

修改了这些东西后,我们会发现数据还是没有。我们还需要修改一些信息。一个很重要的信息就是段头上的高水位信息。在Truncate之前,段头上会记载。前面我们在讲L1块的时候说过,可以看到223后面直接就是225,直接此处跳空,这是因为我们的224是L1位图块,后面紧跟着我们刚刚说的225,226,227,228,229,230,231,232,233。但是问题是,这里看不到后面的234到239?这是因为234到239还是空闲没有格式化过的块,但是它已经被L1锁定了。所以我们现在的高水位的块是234,一般做全表扫描的查询就会查高水位以下(234)的块。我们来看下我们现在的高水位。

BBED> dump /v offset 48 count 16

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets:   48 to   63  Dba:0x00000000

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

00000000 03000000 08000000 83004001 l ..............@.

BBED> dump /v offset 92 count 16

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets:   92 to  107  Dba:0x00000000

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

00000000 03000000 08000000 83004001 l ..............@.

SQL> select dbms_utility.data_block_address_file(to_number('01400083','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('01400083','xxxxxxxx')) as blockno from dual;

FILENO    BLOCKNO

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

5        131

注意看这里的高水位是83004001,转换成文件号和块号,刚好是文件5块131。而前面的00000000,03000000,则代表着是扩展0,block 3,代表着高水位的位置。刚好是第一个extent的第三个块。128是L1,129是L2,130是段头块。而131则是第一个可以使用的数据块。所以这里记录了extent 0,block为3则代表了文件5的131号块。而08000000则代表了extent的大小,我们每个extents是由8个块组成的。

那在truncate之前,我们的高水位的块是文件5块234,我们从块128开始,每8个块是一个extent,234是第14个extent的第三个块。后面的6个块是没有插入数据的空块。这个在前面我dump 最后一个L1块得知。回顾一下,这里下面的块状态显示11111111 11000000。

BBED> dump /v offset 396 count 50

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 224     Offsets:  396 to  445  Dba:0x00000000

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

11111111 11000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

0000                                l ..

所以我们这个地方要把高水位从00000000 03000000 08000000 83004001修改成0d000000 02000000 08000000 ea004001。0d000000代表13,表明是第十四个扩展,02000000代表02,表明是第三个块开始,而08000000还是一样代表着这个扩展是8个块的大小,而ea004001则代表着文件5块234。

BBED> modify /x 0d offset 48

Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130              Offsets:   48 to   63           Dba:0x00000000

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

0d000000 03000000 08000000 83004001

BBED> modify /x 02 offset 52

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130              Offsets:   52 to   67           Dba:0x00000000

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

02000000 08000000 83004001 00000000

BBED> modify /x ea offset 60

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130              Offsets:   60 to   75           Dba:0x00000000

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

ea004001 00000000 00000000 00000000

BBED> dump /v offset 48 count 16

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets:   48 to   63  Dba:0x00000000

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

0d000000 02000000 08000000 ea004001 l ............

BBED> modify /x 0d offset 92

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130              Offsets:   92 to  107           Dba:0x00000000

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

0d000000 03000000 08000000 83004001

BBED> modify /x 02 offset 96

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130              Offsets:   96 to  111           Dba:0x00000000

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

02000000 08000000 83004001 00000000

BBED>  modify /x ea offset 104

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130              Offsets:  104 to  119           Dba:0x00000000

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

ea004001 00000000 00000000 00000000

BBED> dump /v offset 92 count 16

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets:   92 to  107  Dba:0x00000000

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

0d000000 02000000 08000000 ea004001 l ............

BBED> sum apply

Check value for File 0, Block 130:

current = 0x8c54, required = 0x8c54

修改完成之后,刷新buffer cache,然后重新查询。

SQL> alter system flush buffer_cache;

System altered.

SQL> select count(1) from a1.a;

COUNT(1)

----------

142

3.Extents信息恢复

可以看到数据量不对,这是因为我们Truncate之后,在段头上只剩下了一个Extent的信息。而我们的Extents是有14个的,这需要我们在修改如下几个地方。Offset 264代表着我们Extents的数量,,这里修改成0e代表了14个extents。

BBED> modify /x 0e offset 264

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130              Offsets:  264 to  363           Dba:0x00000000

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

0e000000 00000000 ca270100 00000010 80004001 08000000 88004001 08000000

90004001 08000000 98004001 08000000 a0004001 08000000 a8004001 08000000

b0004001 08000000 b8004001 08000000 c0004001 08000000 c8004001 08000000

d0004001

修改完Extents的数量之后,还需要添加对应的Extents Map的信息。因为我们的Extents Map信息也被删除了。从我们的offset 280开始。

BBED> dump /v offset 280 count 100

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets:  280 to  379  Dba:0x00000000

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

80004001 08000000 00000000 00000000 l ..@.............

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000                            l ....

80004001 08000000这个Extents是我们第一个Extents。代表了文件5的块128。我们可以依次类推下列的信息出来。而08000000则代表有8个数据块构成一个Extents。

modify /x 8800 offset 288  modify /x 4001 offset 290  modify /x 08 offset 292

modify /x 9000 offset 296  modify /x 4001 offset 298  modify /x 08 offset 300

modify /x 9800 offset 304  modify /x 4001 offset 306  modify /x 08 offset 308

modify /x a000 offset 312  modify /x 4001 offset 314  modify /x 08 offset 316

modify /x a800 offset 320  modify /x 4001 offset 322  modify /x 08 offset 324

modify /x b000 offset 328  modify /x 4001 offset 330  modify /x 08 offset 332

modify /x b800 offset 336  modify /x 4001 offset 338  modify /x 08 offset 340

modify /x c000 offset 344  modify /x 4001 offset 346  modify /x 08 offset 348

modify /x c800 offset 352  modify /x 4001 offset 354  modify /x 08 offset 356

modify /x d000 offset 360  modify /x 4001 offset 362  modify /x 08 offset 364

modify /x d800 offset 368  modify /x 4001 offset 370  modify /x 08 offset 372

modify /x e000 offset 376  modify /x 4001 offset 378  modify /x 08 offset 380

modify /x e800 offset 384  modify /x 4001 offset 386  modify /x 08 offset 388

BBED> dump /v offset 280 count 128

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets:  280 to  407  Dba:0x00000000

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

80004001 08000000 88004001 08000000 l ..@.......@.....

90004001 08000000 98004001 08000000 l ..@.......@.....

a0004001 08000000 a8004001 08000000 l ........

b0004001 08000000 b8004001 08000000 l ........

c0004001 08000000 c8004001 08000000 l ........

d0004001 08000000 d8004001 08000000 l ........

e0004001 08000000 e8004001 08000000 l ........

00000000 00000000 00000000 00000000 l ................

当然这些Extents Map修改完成之后,我们还需要在添加Auxillary Map。那什么是辅助的Map呢?我们从Offset 2736开始。

BBED> dump /v offset 2736 count 200

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets: 2736 to 2935  Dba:0x00000000

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

80004001 83004001 00000000 00000000 l ..@...@.........

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

00000000 00000000 00000000 00000000 l ................

这里的80004001 83004001,代表这Extents中,L1块的地址和Data Block的地址,可以看到在Extents 1上面,它的L1块是128,而数据块是从131开始的。因为我们的129是L2,130是段头。所以下面我们构造其他的数据的时候,我们也要遵循这个规律。我们的Extents 2,它的L1还是128块,但是它的数据块确是从136开始的。而Extents 3,它的L1就是第二个L1块,也就是144,而它的数据块的开始则是从145开始的。依次类推下去。结果如下:

modify /x 8000 offset 2744  modify /x 4001 offset 2746

modify /x 8800 offset 2748  modify /x 4001 offset 2750

modify /x 9000 offset 2752  modify /x 9000 offset 2754

modify /x 9100 offset 2756  modify /x 4001 offset 2758

modify /x 9000 offset 2760  modify /x 4001 offset 2762

modify /x 9800 offset 2764  modify /x 4001 offset 2766

modify /x a000 offset 2768  modify /x 4001 offset 2770

modify /x a100 offset 2772  modify /x 4001 offset 2774

modify /x a000 offset 2776  modify /x 4001 offset 2778

modify /x a800 offset 2780  modify /x 4001 offset 2782

modify /x b000 offset 2784  modify /x 4001 offset 2786

modify /x b100 offset 2788  modify /x 4001 offset 2790

modify /x b000 offset 2792  modify /x 4001 offset 2794

modify /x b800 offset 2796  modify /x 4001 offset 2798

modify /x c000 offset 2800  modify /x 4001 offset 2802

modify /x c100 offset 2804  modify /x 4001 offset 2806

modify /x c000 offset 2808  modify /x 4001 offset 2810

modify /x c800 offset 2812  modify /x 4001 offset 2814

modify /x d000 offset 2816  modify /x 4001 offset 2818

modify /x d100 offset 2820  modify /x 4001 offset 2822

modify /x d000 offset 2824  modify /x 4001 offset 2826

modify /x d800 offset 2828  modify /x 4001 offset 2830

modify /x e000 offset 2832  modify /x 4001 offset 2834

modify /x e100 offset 2836  modify /x 4001 offset 2838

modify /x e000 offset 2840  modify /x 4001 offset 2842

modify /x e800 offset 2844  modify /x 4001 offset 2846

BBED> dump /v offset 2736 count 128

File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)

Block: 130     Offsets: 2736 to 2863  Dba:0x00000000

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

80004001 83004001 80004001 88004001 l ..@...@...@...@.

90009000 91004001 90004001 98004001 l ......@...@...@.

a0004001 a1004001 a0004001 a8004001 l

b0004001 b1004001 b0004001 b8004001 l

c0004001 c1004001 c0004001 c8004001 l

d0004001 d1004001 d0004001 d8004001 l

e0004001 e1004001 e0004001 e8004001 l

00000000 00000000 00000000 00000000 l ................

修改完成这些后,我们就能够查到我们全部的数据了。

SQL> alter system flush buffer_cache;

System altered.

SQL> select count(1) from a1.a;

COUNT(1)

----------

2775

此时我们切勿执行一些其他的操作,应该尽快的使用CTAS的方式将这个表进行备份或者是导出。因为段头块L2和L1的信息还一些是没有修改的。

SQL> create table a2.a as select * from a1.a;

Table created.

SQL> drop table a1.a;

Table dropped

至此,Truncate恢复完成。仔细的研究你才会发现,其实最重要的是摸清楚整个段的构造情况,只要你对整个段的构造情况,了若指掌,基本上恢复是很简单的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值