列删除的恢复测试 – 不要模仿

首先重申,这个测试是玩的,大家不要借鉴!测试源于群里一个网友的提问。

SQL> show  user
USER is  ROGER

SQL> drop table t;
Table dropped.

SQL> create table t(a number, b varchar2(6));
Table created.

SQL> insert into t values(1, 'roger');

1 row created.

SQL> /

1 row created.

SQL> /

1 row created.

SQL> commit;

Commit complete.

SQL> select * from t;

         A B
---------- ------
         1 roger
         1 roger
         1 roger


SQL> conn roger/roger
Connected.

SQL> drop table t3;

Table dropped.

SQL> create table t3 as select owner,object_name,object_type from dba_objects;

Table created.

SQL> create table t4 as select * from t3;

Table created.

SQL> select owner,object_name,object_id
  2    from dba_objects
  3   where object_name in ('T3','T4');

OWNER                          OBJECT_NAME           OBJECT_ID
------------------------------ -------------------- ----------
ROGER                          T3                        54360
ROGER                          T4                        54361

SQL> analyze table roger.t3 compute statistics;

Table analyzed.

SQL> analyze table roger.t4 compute statistics;

Table analyzed.
开始在作了10046 trace发现了如下操作:
update tab$ set ts#=:2,file#=:3,block#=:4,bobj#=decode(:5,0,null,:5),tab#=decode(:6,0,null,:6),
       intcols=:7,kernelcols=:8,clucols=decode(:9,0,null,:9),audit$=:10,flags=:11,pctfree$=:12,
       pctused$=:13,initrans=:14,maxtrans=:15,rowcnt=:16,blkcnt=:17,empcnt=:18,avgspc=:19,chncnt=:20,
       avgrln=:21,analyzetime=:22,samplesize=:23,cols=:24,property=:25,degree=decode(:26,1,null,:26),
       instances=decode(:27,1,null,:27),dataobj#=:28,avgspc_flb=:29,flbcnt=:30,trigflag=:31,spare1=:32,
       spare2=decode(:33,0,null,:33),spare4=:34,spare6=:35
 where obj#=:1

update obj$ set obj#=:6,type#=:7,ctime=:8,mtime=:9,stime=:10,status=:11,dataobj#=:13,flags=:14,oid$=:15,
       spare1=:16, spare2=:17
 where owner#=:1 and name=:2 and namespace=:3 and(remoteowner=:4 or remoteowner is null
   and :4 is null)and(linkname=:5 or linkname is null and :5 is null)
   and (subname=:12 or subname is null and :12 is null)

delete com$ where obj#=:1 and col#=:2

delete from sys.col_usage$ where obj#= :1 and intcol#= :2

delete from objauth$ where obj#=:1 and col#=:2

delete from col$ where obj#=:1 and intcol#=:2  --

delete from idl_ub1$ where obj#=:1

delete from idl_char$ where obj#=:1

delete from idl_ub2$ where obj#=:1

delete from idl_sb4$ where obj#=:1

delete from error$ where obj#=:1

delete from superobj$ where subobj# = :1

delete from tab_stats$ where obj#=:1
SQL> select * from com$ where obj#=54360;

no rows selected

SQL> select * from sys.col_usage$  where obj#=54360;

no rows selected

SQL> select count(*) from objauth$ where obj#=54360;

  COUNT(*)
----------
         0

SQL> select count(*) from col$ where obj#=54360;

  COUNT(*)
----------
         3

SQL> select count(*) from idl_ub1$ where obj#=54360;

  COUNT(*)
----------
         0

SQL> select count(*) from idl_char$ where obj#=54360;

  COUNT(*)
----------
         0

SQL> select count(*) from idl_ub2$ where obj#=54360;

  COUNT(*)
----------
         0

SQL> select count(*) from idl_sb4$ where obj#=54360;

  COUNT(*)
----------
         0

SQL> select count(*) from error$ where obj#=54360;

  COUNT(*)
----------
         0

SQL> select count(*) from tab_stats$ where obj#=54360;

  COUNT(*)
----------
         0

SQL> select count(*) from superobj$;

  COUNT(*)
----------
         0

经过对比发现,对于列的删除,tab$ 只是改变了如下几个列:
SQL> select COLS,INTCOLS,KERNELCOLS,AVGSPC,AVGRLN from tab$ where obj# in(54360,54361);

      COLS    INTCOLS KERNELCOLS     AVGSPC     AVGRLN
---------- ---------- ---------- ---------- ----------
         3          3          3        834         41
         2          2          2       2272         33

对于 obj$ 而言,如下3个列发生了改变:
SQL> select ctime,mtime,stime,spare2 from obj$ where obj# in(54360,54361);

CTIME               MTIME               STIME                   SPARE2
------------------- ------------------- ------------------- ----------
2012-02-23 04:43:37 2012-02-23 04:43:37 2012-02-23 04:43:37          1
2012-02-23 04:43:46 2012-02-23 04:44:38 2012-02-23 04:44:38          2
对于 col$ 的删除。
SQL> select property from col$ where obj# in(54360,54361) and intcol#=2;

  PROPERTY
----------
     14336
         0
另外还涉及到几个索引,都是object_id 小于56的,不要随便动,下面我通过一个最简单的方式进行操作。
为了安全起见,我备份了一下数据库,如下:
SQL> archive log list;

Database log mode              Archive Mode
Automatic archival             Enabled
Archive destination            /home/ora10g/archivelog
Oldest online log sequence     235
Next log sequence to archive   237
Current log sequence           237


[ora10g@killdb archivelog]$ ls -ltr | head -200 | awk '{print $9}'| xargs rm -rf

[ora10g@killdb ~]$ dbv file=/home/ora10g/oradata/roger/roger02.dbf

DBVERIFY: Release 10.2.0.5.0 - Production on Thu Feb 23 19:57:20 2012
Copyright (c) 1982, 2007, Oracle.  All rights reserved.

DBVERIFY - Verification starting : FILE = /home/ora10g/oradata/roger/roger02.dbf
Page 548 is marked corrupt
Corrupt block relative dba: 0x01800224 (file 6, block 548)
Completely zero block found during dbv:

Page 50403 is marked corrupt
Corrupt block relative dba: 0x0180c4e3 (file 6, block 50403)
Completely zero block found during dbv:

Block Checking: DBA = 25217508, Block Type = KTB-managed data block
data header at 0xb7f5907c
kdbchk: row count in table index incorrect
Page 51684 failed with check code 6125


DBVERIFY - Verification complete

Total Pages Examined         : 64000
Total Pages Processed (Data) : 57061
Total Pages Failing   (Data) : 1
Total Pages Processed (Index): 5978
Total Pages Failing   (Index): 0
Total Pages Processed (Other): 839
Total Pages Processed (Seg)  : 0
Total Pages Failing   (Seg)  : 0
Total Pages Empty            : 120
Total Pages Marked Corrupt   : 2
Total Pages Influx           : 0
Highest block SCN            : 2549808 (0.2549808)


RMAN> run {
2> set maxcorrupt for datafile 6 to 2;
3> backup full as compressed backupset database plus archivelog; }

executing command: SET MAX CORRUPT

Starting backup at 23-FEB-12
current log archived
using channel ORA_DISK_1
channel ORA_DISK_1: starting compressed archive log backupset
channel ORA_DISK_1: specifying archive log(s) in backup set
input archive log thread=1 sequence=230 recid=206 stamp=775116934
input archive log thread=1 sequence=231 recid=207 stamp=775468322
input archive log thread=1 sequence=232 recid=208 stamp=775545128
input archive log thread=1 sequence=233 recid=209 stamp=775548250
input archive log thread=1 sequence=234 recid=210 stamp=775945249
input archive log thread=1 sequence=235 recid=211 stamp=775975475
input archive log thread=1 sequence=236 recid=212 stamp=776029642
input archive log thread=1 sequence=237 recid=213 stamp=776029875
input archive log thread=1 sequence=238 recid=214 stamp=776029937
input archive log thread=1 sequence=239 recid=215 stamp=776030013
input archive log thread=1 sequence=240 recid=216 stamp=776030070
input archive log thread=1 sequence=241 recid=217 stamp=776030315
channel ORA_DISK_1: starting piece 1 at 23-FEB-12
channel ORA_DISK_1: finished piece 1 at 23-FEB-12
piece handle=/home/ora10g/product/10.2/dbs/0qn42i3b_1_1 tag=TAG20120223T195835 comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:37
Finished backup at 23-FEB-12

Starting backup at 23-FEB-12
using channel ORA_DISK_1
channel ORA_DISK_1: starting compressed full datafile backupset
channel ORA_DISK_1: specifying datafile(s) in backupset
input datafile fno=00005 name=/home/ora10g/oradata/roger/roger01.dbf
input datafile fno=00002 name=/home/ora10g/oradata/roger/undotbs01.dbf
input datafile fno=00006 name=/home/ora10g/oradata/roger/roger02.dbf
input datafile fno=00001 name=/home/ora10g/oradata/roger/system01.dbf
input datafile fno=00003 name=/home/ora10g/oradata/roger/sysaux01.dbf
input datafile fno=00004 name=/home/ora10g/oradata/roger/users01.dbf
input datafile fno=00008 name=/home/ora10g/oradata/roger/sqlt_01.dbf
input datafile fno=00007 name=/home/ora10g/oradata/roger/test1.dbf
channel ORA_DISK_1: starting piece 1 at 23-FEB-12
channel ORA_DISK_1: finished piece 1 at 23-FEB-12
piece handle=/home/ora10g/product/10.2/dbs/0rn42i4g_1_1 tag=TAG20120223T195912 comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:01:45
channel ORA_DISK_1: starting compressed full datafile backupset
channel ORA_DISK_1: specifying datafile(s) in backupset
including current control file in backupset
including current SPFILE in backupset
channel ORA_DISK_1: starting piece 1 at 23-FEB-12
channel ORA_DISK_1: finished piece 1 at 23-FEB-12
piece handle=/home/ora10g/product/10.2/dbs/0sn42i7p_1_1 tag=TAG20120223T195912 comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:03
Finished backup at 23-FEB-12

Starting backup at 23-FEB-12
current log archived
using channel ORA_DISK_1
channel ORA_DISK_1: starting compressed archive log backupset
channel ORA_DISK_1: specifying archive log(s) in backup set
input archive log thread=1 sequence=242 recid=218 stamp=776030460
channel ORA_DISK_1: starting piece 1 at 23-FEB-12
channel ORA_DISK_1: finished piece 1 at 23-FEB-12
piece handle=/home/ora10g/product/10.2/dbs/0tn42i7s_1_1 tag=TAG20120223T200100 comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:02
Finished backup at 23-FEB-12
上面的2个坏块不用管,是以前做测试留下的,没有处理,回头有空再处理了,下面继续:
SQL> select obj#,name from obj$ where name in('I_TAB1','I_OBJ3','I_COL1','I_COL2','I_COL3');

      OBJ# NAME
---------- ------------------------------
        38 I_OBJ3
        46 I_COL2
        33 I_TAB1
        47 I_COL3
        45 I_COL1

SQL> update tab$ set cols=3 where obj#=54361;

1 row updated.

SQL> update tab$ set intcols=3  where obj#=54361;

1 row updated.

SQL> update tab$ set KERNELCOLS=3 where obj#=54361;

1 row updated.

SQL> update tab$ set AVGSPC=834  where obj#=54361;

1 row updated.

SQL> update tab$ set avgrln=41 where obj#=54361;

1 row updated.

SQL> update obj$ set mtime='2012-02-23 04:43:46'   where obj#=54361;

1 row updated.

SQL> update obj$ set stime='2012-02-23 04:43:46'  where obj#=54361;

1 row updated.

SQL> update obj$ set spare2=1 where obj#=54361;

1 row updated.

SQL> insert into col$
  2  values
  3    (54361,
  4     3,
  5     3,
  6     19,
  7     0,
  8     'OBJECT_TYPE',
  9     1,
 10     19,
 11     0,
 12     '',
 13     '',
 14     0,
 15     '',
 16     '',
 17     3,
 18     14336,
 19     852,
 20     1,
 21     0,
 22     0,
 23     19,
 24     '',
 25     '',
 26     '');

1 row created.

SQL> commit;

Commit complete.


SQL> set lines 80
SQL> desc roger.t3

 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(30)
 OBJECT_NAME                                        VARCHAR2(128)
 OBJECT_TYPE                                        VARCHAR2(19)

SQL> desc roger.t4

 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 OWNER                                              VARCHAR2(30)
 OBJECT_NAME                                        VARCHAR2(128)
 OBJECT_TYPE                                        VARCHAR2(19)


SQL> select count(*) from t3;

  COUNT(*)
----------
     50918

SQL> select count(*) from t4;

  COUNT(*)
----------
     50918

SQL> set lines 120
SQL> col object_name for a20
SQL> col owner for a20
SQL> select * from t3 where rownum <2;

OWNER                OBJECT_NAME          OBJECT_TYPE
-------------------- -------------------- -------------------
SYS                  ICOL$                TABLE

SQL> select * from t4 where rownum <2;

OWNER                OBJECT_NAME          OBJECT_TYPE
-------------------- -------------------- -------------------
SYS                  ICOL$

SQL> select * from t4 where rownum <10;

OWNER                OBJECT_NAME          OBJECT_TYPE
-------------------- -------------------- -------------------
SYS                  ICOL$
SYS                  I_USER1
SYS                  CON$
SYS                  UNDO$
SYS                  C_COBJ#
SYS                  I_OBJ#
SYS                  PROXY_ROLE_DATA$
SYS                  I_IND1
SYS                  I_CDEF2

9 rows selected.
虽然成功恢复了这个删除的列,但是实际上该列的数据已经没了,因为drop column以后,该列的数据已经
从datafile里面清除了,通过修改数据字典的方式,只是一个欺骗的作用,貌似ODU也不能恢复这种情况。

不过数据库使用闪回的话,应该是可以的,当然是闪回整个db。

补充:对于还没重用的情况,数据其实还在的,看下面的测试:
SQL> conn roger/roger
Connected.

SQL> create table drop_col(a varchar2(4),b varchar2(4));

Table created.

SQL> insert into drop_col values('AA','BB');

1 row created.

SQL> commit;

Commit complete.

SQL> alter table drop_col drop column b;

Table altered.

SQL> select dbms_rowid.rowid_relative_fno(rowid) file#,dbms_rowid.rowid_block_number(rowid) blk#
  2  from drop_col;

     FILE#       BLK#
---------- ----------
         5      29960

SQL> alter system dump datafile 5 block 29960;

System altered.

SQL> select dump('AA',16) from dual;

DUMP('AA',16)
-------------------
Typ=96 Len=2: 41,41

SQL> select dump('BB',16) from dual;

DUMP('BB',16)
-------------------
Typ=96 Len=2: 42,42
BBED> set file 5 block 29960

        FILE#           5
        BLOCK#          29960

BBED> find /c BB

 File: /home/ora10g/oradata/roger/roger01.dbf (5)
 Block: 29960            Offsets: 8186 to 8191           Dba:0x01407508
------------------------------------------------------------------------
 42420106 8268

 <32 bytes per line>


BBED> p rowdata

ub1 rowdata[0]                              @8179     0x2c
ub1 rowdata[1]                              @8180     0x02
ub1 rowdata[2]                              @8181     0x01
ub1 rowdata[3]                              @8182     0x02
ub1 rowdata[4]                              @8183     0x41
ub1 rowdata[5]                              @8184     0x41
ub1 rowdata[6]                              @8185     0x02
ub1 rowdata[7]                              @8186     0x42
ub1 rowdata[8]                              @8187     0x42


在这种情况下,应该是可以直接把rowdata里面的数据给抽取出来的,前面的02是行头,需要跳过。


评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注