[20250506]drop table的恢复2.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 : 126494 D_OID : 126494 CREATED : 2025-05-06 14:48:10 LAST_DDL_TIME : 2025-05-06 14:48:10 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 : 178 PL/SQL procedure successfully completed. 3.恢复测试: SCOTT@book01p> drop table t1 purge ; Table dropped. SCOTT@book01p> create table emp_xxx as select * from emp ; Table created. SCOTT@book01p> @ seg2 emp_xxx SCOTT@book01p> @ pr ============================== SEG_MB : 0 SEG_OWNER : SCOTT SEG_SEGMENT_NAME : EMP_XXX SEG_PARTITION_NAME : SEG_SEGMENT_TYPE : TABLE SEG_TABLESPACE_NAME : USERS BLOCKS : 8 HDRFIL : 12 HDRBLK : 178 PL/SQL procedure successfully completed. --//原来的段头覆盖另外有1个数据块也被破坏,基本破坏了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-06 14:49:09. 37973932 07000D00BF1E0000 D 126494 126494 T1 --//OBJ#=126494就是需要恢复的表,实际上你可以通过logminer确定drop table原来的数据段号。 --//昏,第1次测试OBJ#=125494,非常容易混淆。 SYS@book01p> @ versions obj$ OBJ#,DATAOBJ#,name s '' '' versions_operation='I' VERSIONS_STARTTIME VERSIONS_ENDTIME VERSIONS_STARTSCN VERSIONS_ENDSCN VERSIONS_XID V OBJ# DATAOBJ# NAME -------------------- -------------------- ----------------- --------------- ---------------- - ---------- ---------- ------- 2025-05-06 14:48:11. 2025-05-06 14:49:09. 37973692 37973932 07000B00B81E0000 I 126494 126494 T1 2025-05-06 14:48:17. 37973818 02002000C01E0000 I 126495 126495 T1_BAK 2025-05-06 14:49:18. 37973982 060017006F1E0000 I 126496 126496 EMP_XXX SYS@book01p> @ as_of tab$ OBJ#,DATAOBJ#,ts#,file#,block# s 37973692 obj#=126494 ROWID OBJ# DATAOBJ# TS# FILE# BLOCK# ------------------ ---------- ---------- ---------- ---------- ---------- AAAAACAABAAAH1AAAA 126494 126494 5 12 178 SYS@book01p> @as_of seg$ * s 37973692 HWMINCR=126494 SYS@book01p> @ pr ============================== ROWID : AAAAAIAABAAAJClAAC FILE# : 12 BLOCK# : 178 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 : 126494 SPARE1 : 4325633 SPARE2 : PL/SQL procedure successfully completed. --//获取drop 前的信息。 --//建立与原来数据结构一样的表,修改段号,在扫描数据块应该可以恢复相关信息。 5.注意覆盖问题: --//如何解决在建表覆盖的问题.可以在原表空间增加一个数据文件: ALTER TABLESPACE USERS ADD DATAFILE '/u01/oradata/BOOK/book01p/users02.dbf' SIZE 100M AUTOEXTEND ON NEXT 4M MAXSIZE UNLIMITED; SCOTT@book01p> alter database datafile '/u01/oradata/BOOK/book01p/users01.dbf' offline ; alter database datafile '/u01/oradata/BOOK/book01p/users01.dbf' offline * ERROR at line 1: ORA-01145: offline immediate disallowed unless media recovery enabled SYS@book01p> alter database datafile '/u01/oradata/BOOK/book01p/users01.dbf' offline drop; Database altered. --//注:因为我的测试环境没有打开归档,导致直接offline报错,加入drop没有问题,注意并非真正意思删除。 SYS@book01p> recover datafile 12; Media recovery complete. --//顺手先recover datafile 12;以后可以直接online。 SCOTT@book01p> create table t1_drop SEGMENT CREATION IMMEDIATE as select * from all_objects where 0=1; Table created. SCOTT@book01p> select * from dba_extents where segment_name='T1_DROP'; SCOTT@book01p> @ pr ============================== OWNER : SCOTT SEGMENT_NAME : T1_DROP PARTITION_NAME : SEGMENT_TYPE : TABLE TABLESPACE_NAME : USERS EXTENT_ID : 0 FILE_ID : 16 BLOCK_ID : 128 BYTES : 65536 BLOCKS : 8 RELATIVE_FNO : 16 PL/SQL procedure successfully completed. --//没有使用数据文件/u01/oradata/BOOK/book01p/users01.dbf。 --//建立表空间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 : 126498 D_OID : 126498 CREATED : 2025-05-06 15:02:48 LAST_DDL_TIME : 2025-05-06 15:02:48 PL/SQL procedure successfully completed. --//修改t1_drop的数据段号等于原来t1表的数据段号。 SYS@book01p> update (select OBJ#, DATAOBJ# , OWNER#, NAME from obj$ where obj#=126498) set DATAOBJ#=126494; 1 row updated. SYS@book01p> commit ; Commit complete. SYS@book01p> alter system flush shared_pool; System altered. SYS@book01p> alter database datafile '/u01/oradata/BOOK/book01p/users01.dbf' online ; Database altered. SCOTT@book01p> select OWNER,OBJECT_NAME from t1_drop where rowid = dbms_rowid.rowid_create(1,126494,12,180,0); OWNER OBJECT_NAME ------------------------------ ------------------------------ SYS HIST_HEAD$ SYS@book01p> set timing on SYS@book01p> @ txt/truncT.txt SCOTT T1_DROP SCOTT BAK_T1 PL/SQL procedure successfully completed. Elapsed: 00:01:07.88 SYS@book01p> set timing off SCOTT@book01p> select count(*) from bak_t1; COUNT(*) ---------- 69571 SCOTT@book01p> select count(*) from t1_bak; COUNT(*) ---------- 69886 --//69886-69571 = 315,丢失的了315行。 SCOTT@book01p> select * from bak_t1 minus select * from t1_bak ; no rows selected --//说明恢复的数据问题。 6.疑问: SCOTT@book01p> select rowid from t1_bak where rownum=1; ROWID ------------------ AAAe4fAAMAAAGA7AAA SCOTT@book01p> select count(*) from t1_bak where rowid between 'AAAe4fAAMAAAGA7AAA' and 'AAAe4fAAMAAAGA7BBB'; COUNT(*) ---------- 66 --//按照道理仅仅破坏1个数据块,为什么丢失了316/66 = 4.78,将近5块呢,实际上建立表exp_xxx时,建立1个extents占用8块。 SCOTT@book01p> select * from dba_extents where segment_name='EMP_XXX'; SCOTT@book01p> @ pr ============================== OWNER : SCOTT SEGMENT_NAME : EMP_XXX PARTITION_NAME : SEGMENT_TYPE : TABLE TABLESPACE_NAME : USERS EXTENT_ID : 0 FILE_ID : 12 BLOCK_ID : 176 BYTES : 65536 BLOCKS : 8 RELATIVE_FNO : 12 PL/SQL procedure successfully completed. --//176,177,178没有数据。179已经被emp_xxx占用,剩下180,181,182,183块还是有数据,看看能否恢复。 SCOTT@book01p> select OWNER,OBJECT_NAME from t1_drop where rowid = dbms_rowid.rowid_create(1,126494,12,180,0); OWNER OBJECT_NAME ----- ----------- SYS HIST_HEAD$ SCOTT@book01p> select OWNER,OBJECT_NAME from t1_drop where rowid = dbms_rowid.rowid_create(1,126494,12,181,0); OWNER OBJECT_NAME ----- ----------- SYS MIGRATE$ SCOTT@book01p> select OWNER,OBJECT_NAME from t1_drop where rowid = dbms_rowid.rowid_create(1,126494,12,182,0); OWNER OBJECT_NAME ----- ----------- SYS CDB_TS$ SCOTT@book01p> select OWNER,OBJECT_NAME from t1_drop where rowid = dbms_rowid.rowid_create(1,126494,12,183,0); OWNER OBJECT_NAME ----- ----------- SYS I_JIJOIN$ --//而使用truncT.sql脚本无法扫描这些数据块。通过我前面的bbed扫描确定数据段号的方式就没有问题。 7.改用bbed扫描数据文件看看: --//$ cd bbed ; --//$ rm log.bbd --//确定最大块号 SYS@book01p> select * from dba_DATA_FILES where file_id=12 2 @ pr ============================== FILE_NAME : /u01/oradata/BOOK/book01p/users01.dbf FILE_ID : 12 TABLESPACE_NAME : USERS BYTES : 267386880 BLOCKS : 32640 STATUS : AVAILABLE RELATIVE_FNO : 12 AUTOEXTENSIBLE : YES MAXBYTES : 34359721984 MAXBLOCKS : 4194302 INCREMENT_BY : 160 USER_BYTES : 266338304 USER_BLOCKS : 32512 ONLINE_STATUS : ONLINE LOST_WRITE_PROTECT : OFF PL/SQL procedure successfully completed. --//确定那些数据块的段号等于126494。 $ seq 128 1 32640 | xargs -IQ echo p /d dba 12,Q ktbbhsid.ktbbhsg1 | rlbbed > /dev/null $ grep -B1 " 126494$" log.bbd | grep ktbbhsid.ktbbhsg1 | head -7 BBED> p /d dba 12,180 ktbbhsid.ktbbhsg1 BBED> p /d dba 12,181 ktbbhsid.ktbbhsg1 BBED> p /d dba 12,182 ktbbhsid.ktbbhsg1 BBED> p /d dba 12,183 ktbbhsid.ktbbhsg1 BBED> p /d dba 12,184 ktbbhsid.ktbbhsg1 BBED> p /d dba 12,185 ktbbhsid.ktbbhsg1 BBED> p /d dba 12,186 ktbbhsid.ktbbhsg1 --//将需要扫描的数据块保存在文本scan.txt文件中。 $ grep -B1 126494$ log.bbd | grep ktbbhsid.ktbbhsg1 >| scan.txt SYS@book01p> create table scott.scanblock ( file_id number,block_id number ) tablespace TSP_AUDIT; Table created. --//注意建立的新表一定不能使用原来的表空间,避免覆盖。 $ awk '{print $5}' scan.txt | sed 's/^/insert into scanblock values (/;s/$/);/' >| scan1.txt $ head -2 scan1.txt ; tail -2 scan1.txt insert into scanblock values (12,180); insert into scanblock values (12,181); insert into scanblock values (12,24630); insert into scanblock values (12,24631); --//执行@scan1.txt.注意提交。 --//SCOTT@book01p> truncate table BAK_T1; --//Table truncated. SYS@book01p> set timing on SYS@book01p> @ truncT.txt SCOTT T1_DROP SCOTT BAK_T1 PL/SQL procedure successfully completed. Elapsed: 00:00:56.70 SYS@book01p> set timing off SCOTT@book01p> select count(*) from bak_T1; COUNT(*) ---------- 69819 SCOTT@book01p> select count(*) from T1_BAK; COUNT(*) ---------- 69886 --//69886-69819 = 67,这样恢复丢失67条。(注:实际丢失66条)。 --//还是存在小小疑问。 SCOTT@book01p> select rowid,DBMS_ROWID.ROWID_BLOCK_NUMBER (rowid) b from t1_bak where rownum<=1; ROWID B ------------------ ---------- AAAe4fAAMAAAGA7AAA 24635 SCOTT@book01p> select count(*) from t1_bak where DBMS_ROWID.ROWID_BLOCK_NUMBER (rowid)=24635; COUNT(*) ---------- 66 SCOTT@book01p> select * from ( select * from (select count(*) a ,DBMS_ROWID.ROWID_BLOCK_NUMBER (rowid) b from t1_bak group by DBMS_ROWID.ROWID_BLOCK_NUMBER (rowid) )) where a=67 ; no rows selected --//保存的备份表也没有67条记录的数据块。噢回看才明白问题在那里,t1_bak建立如下: SCOTT@book01p> create table t1_bak as select * from all_objects; Table created. --//这样多1条记录。应该写成: create table t1_bak as select * from t1; --//测试疏忽了。 SCOTT@book01p> select count(*) from t1_bak where object_name='T1'; COUNT(*) ---------- 1 SCOTT@book01p> select count(*) from bak_t1 where object_name='T1'; COUNT(*) ---------- 0 SCOTT@book01p> select * from bak_t1 minus select * from t1_bak; no rows selected --//说明恢复的数据没有任何问题。 --//理论讲确定扫描那些数据块的方法以及原始方法执行实际差别不大,但是前者丢失数据要少一些。 8.收尾还原: SYS@book01p> update (select OBJ#, DATAOBJ# , OWNER#, NAME from obj$ where obj#=126498) set DATAOBJ#=126498; 1 row updated. SYS@book01p> commit ; Commit complete. SYS@book01p> alter system flush shared_pool; System altered. 9.执行脚本另外写1个文章贴出。
[20250506]drop table的恢复2.txt
来源:这里教程网
时间:2026-03-03 21:58:28
作者:
编辑推荐:
下一篇:
相关推荐
-
雷神推出 MIX PRO II 迷你主机:基于 Ultra 200H,玻璃上盖 + ARGB 灯效
2 月 9 日消息,雷神 (THUNDEROBOT) 现已宣布推出基于英
-
制造商 Musnap 推出彩色墨水屏电纸书 Ocean C:支持手写笔、第三方安卓应用
2 月 10 日消息,制造商 Musnap 现已在海外推出一款 Oce
热文推荐
- INFO OGG-06441 不是告警而容易忽略的错误
INFO OGG-06441 不是告警而容易忽略的错误
26-03-03 - 小米没想到,自家车主不服管
小米没想到,自家车主不服管
26-03-03 - 聊了十年“社交梦”,支付宝终于打通了这个电话
聊了十年“社交梦”,支付宝终于打通了这个电话
26-03-03 - 中国最良心的两个企业家,联手了
中国最良心的两个企业家,联手了
26-03-03 - Oracle官方MySQL+APEX+AI限时免费预约流程大全
Oracle官方MySQL+APEX+AI限时免费预约流程大全
26-03-03 - 国产密码新时代!华测国密 SSL 证书解锁安全新高度
国产密码新时代!华测国密 SSL 证书解锁安全新高度
26-03-03 - 数据库管理-第325期 ADG Failover后该做啥(20250513)
- 评测揭秘!同一份外卖,拼好饭为什么更有性价比?
评测揭秘!同一份外卖,拼好饭为什么更有性价比?
26-03-03 - 京东敢烧钱做外卖,原来是因为电商赚麻了
京东敢烧钱做外卖,原来是因为电商赚麻了
26-03-03 - 深入浅出 Rust 并发:RwLock 与 Mutex 在 Tauri 项目中的实践
