truncate或者drop后一定可以恢复数据吗

| No Comments

有朋友在MSN上问我"truncatedrop后一定可以恢复数据吗?"

我回答说只要数据没有被覆盖,那么就一定可以

他接着问"那如果这个表里有脏块怎么办?按我的理解,如果有脏块的话,这些脏块在truncate或者drop后是会丢失的。"

 

其实这位朋友所担心的问题并不会发生,因为oracle在做truncate或者drop的时候会触发object checkpoint

 

我们来看一个实例:

SQL_testdb>create table test_truncate_recovery as select * from dba_users where 1=2;

 

Table created.

 

SQL_testdb>insert into test_truncate_recovery select * from dba_users;

 

29 rows created.

 

SQL_testdb>commit;

 

Commit complete.

 

SQL_testdb>select t.username,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location from test_truncate_recovery t;

 

USERNAME                       LOCATION

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

SYS                             1_53498

SYSTEM                         1_53498

......省略显示部分内容

QS_CS                          1_53498

 

29 rows selected.

从结果里我们可以看到现在表test_truncate_recovery里有29条记录,且第一条记录(即usernameSYS的那条记录)所在的物理地址为file 1block 53498

 

我们去看一下这29条记录所在的block

BBED> set file 1

        FILE#           1

 

BBED> set block 53498

        BLOCK#          53498

 

BBED> map /v

 File: /dras20/testdb/system01.dbf (1)

 Block: 53498                                 Dba:0x0040d0fa

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

BBED-00400: invalid blocktype (00)

 

 

BBED> dump

 File: /dras20/testdb/system01.dbf (1)

 Block: 53498            Offsets:    0 to  511           Dba:0x0040d0fa

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

 00020000 0040d0fa 00000000 00000105 d1bc0000 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

 

 <32 bytes per line>

从结果里我们可以看到这29条记录还没有被写回到datafile里,也就是说这29条记录现在还都在脏块里。

 

现在我们来对表test_truncate_recoverytruncate操作:

SQL_testdb>truncate table test_truncate_recovery;

 

Table truncated.

 

执行完后再去看一下这29条记录所在的block

BBED> set file 1

        FILE#           1

 

BBED> set block 53498

        BLOCK#          53498

 

BBED> map

 File: /dras20/testdb/system01.dbf (1)

 Block: 53498                                 Dba:0x0040d0fa

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

 KTB Data Block (Table/Cluster)

 

 struct kcbh, 20 bytes                      @0      

 struct ktbbh, 72 bytes                     @20     

 struct kdbh, 14 bytes                      @92     

 struct kdbt[1], 4 bytes                    @106    

 sb2 kdbr[29]                               @110    

 ub1 freespace[4881]                        @168    

 ub1 rowdata[3139]                          @5049   

 ub4 tailchk                                @8188    

 

BBED> p *kdbr[0]

rowdata[0]

----------

ub1 rowdata[0]                              @5049     0x2c

 

BBED> x /rcncc

rowdata[0]                                  @5049   

----------

flag@5049: 0x2c (KDRHFL, KDRHFF, KDRHFH)

lock@5050: 0x01

cols@5051:   11

 

col    0[3] @5052: SYS

col    1[1] @5056: 0

col   2[16] @5058: 8A8F025737A9097A

col    3[4] @5075: OPEN

col    4[0] @5080: *NULL*

col    5[0] @5081: *NULL*

col    6[6] @5082: SYSTEM

col    7[4] @5089: TEMP

col    8[7] @5094: xf....#

col    9[7] @5102: DEFAULT

col   10[9] @5110: SYS_GROUP

从结果里我们可以看到在执行了truncate操作后,刚才那29条脏数据已经被写回到了datafile里。

 

如法炮制,可以测一下drop后的情况:

SQL_testdb>create table test_drop_recovery as select * from dba_users where 1=2;

 

Table created.

 

SQL_testdb>insert into test_drop_recovery select * from dba_users;

 

29 rows created.

 

SQL_testdb>commit;

 

Commit complete.

 

SQL_testdb>select t.username,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location from test_drop_recovery t;

 

USERNAME                       LOCATION

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

SYS                            1_54018

SYSTEM                         1_54018

......省略显示部分内容

QS_CS                          1_54018

 

29 rows selected.

 

BBED> set file 1

        FILE#           1

 

BBED> set block 54018

        BLOCK#          54018

 

BBED> map /v

 File: /dras20/testdb/system01.dbf (1)

 Block: 54018                                 Dba:0x0040d302

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

BBED-00400: invalid blocktype (00)

 

BBED> dump

 File: /dras20/testdb/system01.dbf (1)

 Block: 54018            Offsets:    0 to  511           Dba:0x0040d302

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

 00020000 0040d302 00000000 00000105 d2440000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 ......省略显示部分内容

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 

 <32 bytes per line>

 

SQL_testdb>drop table test_drop_recovery;

 

Table dropped.

 

BBED> set file 1

        FILE#           1

 

BBED> set block 54018

        BLOCK#          54018

 

BBED> map

 File: /dras20/testdb/system01.dbf (1)

 Block: 54018                                 Dba:0x0040d302

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

 KTB Data Block (Table/Cluster)

 

 struct kcbh, 20 bytes                      @0      

 struct ktbbh, 72 bytes                     @20     

 struct kdbh, 14 bytes                      @92     

 struct kdbt[1], 4 bytes                    @106    

 sb2 kdbr[29]                               @110    

 ub1 freespace[4881]                        @168    

 ub1 rowdata[3139]                          @5049   

 ub4 tailchk                                @8188 

 

BBED> p *kdbr[0]

rowdata[0]

----------

ub1 rowdata[0]                              @5049     0x2c

 

BBED> x /rcncc

rowdata[0]                                  @5049   

----------

flag@5049: 0x2c (KDRHFL, KDRHFF, KDRHFH)

lock@5050: 0x01

cols@5051:   11

 

col    0[3] @5052: SYS

col    1[1] @5056: 0

col   2[16] @5058: 8A8F025737A9097A

col    3[4] @5075: OPEN

col    4[0] @5080: *NULL*

col    5[0] @5081: *NULL*

col    6[6] @5082: SYSTEM

col    7[4] @5089: TEMP

col    8[7] @5094: xf....#

col    9[7] @5102: DEFAULT

col   10[9] @5110: SYS_GROUP

 

所以我们说----正是因为oracle的这种object checkpoint机制,就保证了只要truncatedrop后数据没有被覆盖,那么被truncatedrop掉的数据是一定是可以恢复出来的!

Leave a comment