ITPub博客

首页 > 数据库 > Oracle > [20250505]drop table的恢复.txt

[20250505]drop table的恢复.txt

原创 Oracle 作者:lfree 时间:2025-05-07 20:33:34 0 删除 编辑

[20250505]drop table的恢复.txt

--//尝试drop table的恢复,前提没有备份的情况不得已为之的方法,前面测试提到drop table时清除段头里面的Extent Map以及
--//Auxillary Map的信息。这样通过建立新表的方式也只能像truncate table的方式通过rowid扫描数据块来恢复,做一个完整的测试说
--//明问题:

1.环境:
SCOTT@book01p> @ ver2
==============================
PORT_STRING                   : x86_64/Linux 2.4.xx
VERSION                       : 21.0.0.0.0
BANNER                        : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
BANNER_FULL                   : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
BANNER_LEGACY                 : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
CON_ID                        : 0
PL/SQL procedure successfully completed.

2.测试环境建立:
SCOTT@book01p> create table t1 as select * from all_objects;
Table created.

SCOTT@book01p> create table t1_bak as select * from all_objects;
Table created.
--//t1_bak注意目的为了检验drop table的情况。

SCOTT@book01p> @ o2 t1
SCOTT@book01p> @ pr
==============================
O_OWNER                       : SCOTT
O_OBJECT_NAME                 : T1
O_OBJECT_TYPE                 : TABLE
SEG_PART_NAME                 :
O_STATUS                      : VALID
OID                           : 125494
D_OID                         : 125494
CREATED                       : 2025-05-05 09:05:53
LAST_DDL_TIME                 : 2025-05-05 09:05:53
PL/SQL procedure successfully completed.

SCOTT@book01p> @ seg2 t1
SCOTT@book01p> @ pr
==============================
SEG_MB                        : 12
SEG_OWNER                     : SCOTT
SEG_SEGMENT_NAME              : T1
SEG_PARTITION_NAME            :
SEG_SEGMENT_TYPE              : TABLE
SEG_TABLESPACE_NAME           : USERS
BLOCKS                        : 1536
HDRFIL                        : 12
HDRBLK                        : 170
PL/SQL procedure successfully completed.

3.恢复测试:
SCOTT@book01p> drop table t1 purge ;
Table dropped.

SCOTT@book01p> create table emp_bak as select * from emp ;
Table created.

SCOTT@book01p> @ seg2 emp_bak
SCOTT@book01p> @ pr
==============================
SEG_MB                        : 0
SEG_OWNER                     : SCOTT
SEG_SEGMENT_NAME              : EMP_BAK
SEG_PARTITION_NAME            :
SEG_SEGMENT_TYPE              : TABLE
SEG_TABLESPACE_NAME           : USERS
BLOCKS                        : 8
HDRFIL                        : 12
HDRBLK                        : 170
PL/SQL procedure successfully completed.
--//原来的段头覆盖另外有1个数据块也被破坏。

4.确定drop table的段头。

SYS@book01p> @ versions obj$ OBJ#,DATAOBJ#,name s '' '' versions_operation='D'
VERSIONS_STARTTIME   VERSIONS_ENDTIME     VERSIONS_STARTSCN VERSIONS_ENDSCN VERSIONS_XID     V       OBJ#   DATAOBJ# NAME
-------------------- -------------------- ----------------- --------------- ---------------- - ---------- ---------- ------
2025-05-05 09:01:32.                               36801365                 07001F00621E0000 D     125490     125492 BAK_T
2025-05-05 09:04:47.                               36803040                 01000A00341E0000 D     125491     125491 T_BAK
2025-05-05 09:09:44.                               36803972                 08000100C01E0000 D     125494     125494 T1
--//前面2个我测试前删除的表,最后1个OBJ#=125494就是需要恢复的表,实际上你可以通过logminer确定drop table原来的数据段号。

SYS@book01p> @ versions obj$ OBJ#,DATAOBJ#,name s '' '' OBJ#=125494
VERSIONS_STARTTIME   VERSIONS_ENDTIME     VERSIONS_STARTSCN VERSIONS_ENDSCN VERSIONS_XID     V       OBJ#   DATAOBJ# NAME
-------------------- -------------------- ----------------- --------------- ---------------- - ---------- ---------- ------
2025-05-05 09:05:53. 2025-05-05 09:09:44.          36803312        36803972 0A000400701E0000 I     125494     125494 T1
2025-05-05 09:09:44.                               36803972                 08000100C01E0000 D     125494     125494 T1

SYS@book01p> @ as_of tab$ OBJ#,DATAOBJ#,ts#,file#,block# s 36803312 obj#=125494
ROWID                    OBJ#   DATAOBJ#        TS#      FILE#     BLOCK#
------------------ ---------- ---------- ---------- ---------- ----------
AAAAACAABAAAH0yAAA     125494     125494          5         12        170

SYS@book01p> @as_of seg$ * s 36803312  HWMINCR=125494
SYS@book01p> @ pr
==============================
ROWID                         : AAAAAIAABAAAIygAAZ
FILE#                         : 12
BLOCK#                        : 170
TYPE#                         : 5
TS#                           : 5
BLOCKS                        : 1536
EXTENTS                       : 27
INIEXTS                       : 8
MINEXTS                       : 1
MAXEXTS                       : 2147483645
EXTSIZE                       : 128
EXTPCT                        : 0
USER#                         : 109
LISTS                         : 0
GROUPS                        : 0
BITMAPRANGES                  : 2147483645
CACHEHINT                     : 0
SCANHINT                      : 0
HWMINCR                       : 125494
SPARE1                        : 4325633
SPARE2                        :
PL/SQL procedure successfully completed.
--//获取drop 前的信息。

--//建立与原来数据结构一样的表,修改段号,在扫描数据块应该可以恢复相关信息。

SCOTT@book01p> create table t1_drop SEGMENT CREATION IMMEDIATE as select * from all_objects where 0=1;
Table created.

--//建立表空间TSP_AUDIT略。
--//ALTER USER SCOTT QUOTA UNLIMITED ON TSP_AUDIT;

SCOTT@book01p> create table bak_t1 tablespace TSP_AUDIT as select * from scott.t1_drop where 0=1;
Table created.

--//建立新表在原来表空间,只要没有记录插入,不会覆盖(错误!!看后面的测试),另外建立的表要加入SEGMENT CREATION IMMEDIATE,不然
--//oracle认为是空表,无法通过rowid方式读取。扫描获得信息插入的表bak_t1放在另外的表空间,避免覆盖原来的数据文件信息。

SCOTT@book01p> @ o2 t1_drop
SCOTT@book01p>  @pr
==============================
O_OWNER                       : SCOTT
O_OBJECT_NAME                 : T1_DROP
O_OBJECT_TYPE                 : TABLE
SEG_PART_NAME                 :
O_STATUS                      : VALID
OID                           : 125500
D_OID                         : 125500
CREATED                       : 2025-05-05 09:19:58
LAST_DDL_TIME                 : 2025-05-05 09:19:58
PL/SQL procedure successfully completed.

--//修改t1_drop的数据段号等于原来t1表的数据段号。

SYS@book01p> update (select OBJ#,   DATAOBJ#  ,   OWNER#, NAME from obj$ where obj#=125500) set DATAOBJ#=125494;
1 row updated.

SYS@book01p> commit ;
Commit complete.

SYS@book01p> alter system flush shared_pool;
System altered.

SYS@book01p> alter system flush shared_pool;
System altered.

SCOTT@book01p> select OWNER,OBJECT_NAME from t1_drop where rowid = dbms_rowid.rowid_create(1,125494,12,175,0);
OWNER                          OBJECT_NAME
------------------------------ ------------------------------
SYS                            I_JIJOIN$

SCOTT@book01p> select OWNER,OBJECT_NAME from t1_drop where rowid = dbms_rowid.rowid_create(1,125494,12,176,0);
select OWNER,OBJECT_NAME from t1_drop where rowid = dbms_rowid.rowid_create(1,125494,12,176,0)
*
ERROR at line 1:
ORA-01410: invalid ROWID
--//嗯,1个OK,另外1个报错。

SCOTT@book01p> @ seg2 t1_drop
SCOTT@book01p>  @pr
==============================
SEG_MB                        : 0
SEG_OWNER                     : SCOTT
SEG_SEGMENT_NAME              : T1_DROP
SEG_PARTITION_NAME            :
SEG_SEGMENT_TYPE              : TABLE
SEG_TABLESPACE_NAME           : USERS
BLOCKS                        : 8
HDRFIL                        : 12
HDRBLK                        : 178
PL/SQL procedure successfully completed.

SCOTT@book01p> select * from dba_extents where segment_name='T1_DROP';
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE       TABLESPACE_NAME  EXTENT_ID    FILE_ID   BLOCK_ID      BYTES     BLOCKS RELATIVE_FNO
----- ------------ -------------- ------------------ --------------- ---------- ---------- ---------- ---------- ---------- ------------
SCOTT T1_DROP                     TABLE              USERS                    0         12        176      65536          8           12
--//噢,我忽略问题,就是新建立的表要分配新段,建立新的段头,等于覆盖其中3个数据块。先不管这些,继续恢复.

SYS@book01p> set timing on
SYS@book01p> @ txt/truncT.txt SCOTT T1_DROP SCOTT BAK_T1
PL/SQL procedure successfully completed.
Elapsed: 00:01:03.00
SYS@book01p> set timing off

SCOTT@book01p> select count(*) from bak_t1;
  COUNT(*)
----------
     69389

COTT@book01p> select count(*) from t1_bak;
  COUNT(*)
----------
     69880

SCOTT@book01p> select avg(A) from (select count(*) a ,DBMS_ROWID.ROWID_BLOCK_NUMBER (rowid) from t1_bak group by DBMS_ROWID.ROWID_BLOCK_NUMBER (rowid));

    AVG(A)
----------
 47.412483
    
--//69880-69389=491,丢失的了491行。平均每个数据块有47条记录(最小33,最大63),491/47=10.44,大约10-11个数据块没有恢复。
--//建立的表emp_bak占了64K,前面段头3块不算,占用1个数据块,4块含有原来的数据。
--//而建立的新表T1_DROP虽然没有数据,破坏了3个原来的数据块,。剩下5块含有原来的数据。
--//按照以上推断,原始脚本少扫描这16块,9个数据块,其中4个数据块已经破坏。3个其他数据块没有数据。

--//因为里面的扫描范围是:
(SELECT relative_fno, block_id, blocks FROM dba_extents WHERE owner = v_owner AND segment_name = v_table AND extent_id = 0
          UNION ALL
          SELECT relative_fno, block_id, blocks FROM dba_free_space WHERE tablespace_name = v_tablespace
          UNION ALL
          SELECT relative_fno, block_id, blocks
            FROM (SELECT relative_fno
                        ,block_id
                        ,blocks
                        ,ROW_NUMBER () OVER (PARTITION BY owner, segment_name, partition_name ORDER BY extent_id DESC)
                            rn
                    FROM dba_extents
                   WHERE tablespace_name = v_tablespace AND extent_id > 0)
           WHERE rn = 1)
--//最后1个条件extent_id > 0的情况少考虑drop table建立新表的情况。

SCOTT@book01p> select * from bak_t1 minus select * from t1_bak ;
no rows selected
--//说明恢复的数据问题。

--//还原:
SYS@book01p> update (select OBJ#,   DATAOBJ#  ,   OWNER#, NAME from obj$ where obj#=125500) set DATAOBJ#=125500;
1 row updated.

SYS@book01p> commit ;
Commit complete.

--//如何解决在建表覆盖的问题.可以在原表空间增加一个数据文件:
ALTER TABLESPACE USERS
  ADD DATAFILE '/u01/oradata/BOOK/book01p/users02.dbf'
  SIZE 100M
  AUTOEXTEND ON
  NEXT 4M
  MAXSIZE UNLIMITED;

create table t1_drop as select * from all_objects where 0=1;
alter  table t1_drop allocate extent ( datafile '/u01/oradata/BOOK/book01p/users02.dbf' size 64K);
--//后面的测试发现这种方法行不通。

5.补充测试看看:

SCOTT@book01p> drop table t1_drop purge ;
Table dropped.

ALTER TABLESPACE USERS
  ADD DATAFILE '/u01/oradata/BOOK/book01p/users02.dbf'
  SIZE 100M
  AUTOEXTEND ON
  NEXT 4M
  MAXSIZE UNLIMITED;

SCOTT@book01p> create table t1_drop as select * from all_objects where 0=1;
Table created.

SCOTT@book01p> alter table t1_drop allocate extent ( datafile '/u01/oradata/BOOK/book01p/users02.dbf' size 8K);
Table altered.

SCOTT@book01p> @ o2 t1_drop
SCOTT@book01p> @ pr
==============================
O_OWNER                       : SCOTT
O_OBJECT_NAME                 : T1_DROP
O_OBJECT_TYPE                 : TABLE
SEG_PART_NAME                 :
O_STATUS                      : VALID
OID                           : 125503
D_OID                         : 125503
CREATED                       : 2025-05-05 09:57:24
LAST_DDL_TIME                 : 2025-05-05 09:57:39
PL/SQL procedure successfully completed.

COTT@book01p> select * from dba_extents where segment_name='T1_DROP';
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE TABLESPACE_NAME  EXTENT_ID    FILE_ID   BLOCK_ID      BYTES     BLOCKS RELATIVE_FNO
----- ------------ -------------- ------------ --------------- ---------- ---------- ---------- ---------- ---------- ------------
SCOTT T1_DROP                     TABLE        USERS                    0         12        176      65536          8           12
SCOTT T1_DROP                     TABLE        USERS                    1         14        128      65536          8           14
--//不行。如何解决这个问题,另外写一篇blog说明。

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

请登录后发表评论 登录
全部评论
熟悉oracle相关技术,擅长sql优化,rman备份与恢复,熟悉linux shell编程。

注册时间:2008-01-03

  • 博文量
    4006
  • 访问量
    7969783