暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

oracle truncate 恢复脚本

原创 四九年入国军 2025-01-10
275
--恢复思路如下:

通过logminer或者redodump找到dataobj#的变化(用于update obj$里的dataobj#)
使用dbms_rowid.rowid_create抽取该表空间匹配truncate前dataobj#的block里的数据


--抽取的范围也有两种思路:

该表的第一个extent、该表空间的free space、该表空间所有segment的最后一个extent(因为truncate的空间可能已经被其他segment使用,可以抽取LHWM-HHWM之间还未格式化的block)



--测试

SQL> create table scott.test20250110 as select * from dba_objects;

Table created.

SQL> select count(1) from scott.test20250110;

  COUNT(1)
----------
     86349

SQL> truncate table scott.test20250110;

Table truncated.

SQL> 



--1、通过logminer或者redodump找到dataobj#的变化
----因为表可能会truncate过多次,原dataobj#不一定就等于obj#,所以需要通过redo来确认,如果最小补充日志没有打开,logminer可能会有遗漏。
----如果遗漏则使用redodump来寻找。

select obj#,dataobj# from obj$ where name='TEST20250110';

      OBJ#   DATAOBJ#
---------- ----------
     90675      90676
	 
	 
	 
	 
--通过redo确认,需要归档模式
select SQL_REDO from V$LOGMNR_CONTENTS where table_name='OBJ$' and SQL_REDO LIKE '%90675%';



--2、由于需要根据dataobj#去匹配,所以需要修改obj$,修改完成之后需要flush shared_pool
----注意:如果有lob,truncate不会更改lob index的dataobj#,只需要修改lob的dataobj#即可

--修改前先提前创建好临时表
create table SYS.test20250110_new as select *from  scott.test20250110;

SQL> update obj$ set dataobj#=90675 where obj#=90675;

1 row updated.

SQL> commit;

Commit complete.

SQL> alter system flush shared_pool;

System altered.

设置表空间为read only,避免数据被覆盖
SQL> alter tablespace users read only;

Tablespace altered.


--3、恢复脚本
由于需要根据dataobj#去匹配,所以需要修改obj$,修改完成之后需要flush shared_pool
注意:如果有lob,truncate不会更改lob index的dataobj#,只需要修改lob的dataobj#即可


--具体抽取脚本如下:
--注意:恢复的表需要在重新指定一个表空间,避免覆盖数据。本脚本示例将表恢复到了system表空间。
----如果还指向原表空间恢复时间会很长很长,或者卡主不动
----如果指定非原表空间会很快出结果

declare
   v_fno number;
   v_s_bno number;
   v_e_bno number;
   v_rowid rowid;
   nrows number;
   v_owner varchar2(100):='SCOTT';
   v_table varchar2(100):='TEST20250110';
   v_o_owner varchar2(100):='SCOTT';
   v_o_table varchar2(100):='TEST20250110_NEW';
   v_dataobj number;
   v_sql varchar2(4000);
   v_tablespace varchar2(100);
begin
   select data_object_id into v_dataobj from dba_objects where owner=v_owner and object_name=v_table;
   select tablespace_name into v_tablespace from dba_tables where owner=v_owner and table_name=v_table;
   for i in (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) loop
   v_fno:=i.relative_fno;
   v_s_bno:=i.block_id;
   v_e_bno:=i.block_id+i.blocks-1;
       for j in v_s_bno .. v_e_bno loop
        begin
         for x in 0 .. 999 loop
           v_rowid:=dbms_rowid.rowid_create(1,v_dataobj,v_fno,j,x);
           v_sql:='insert into '||v_o_owner||'.'||v_o_table||' select * from '||v_owner||'.'||v_table||' where rowid=:1';
                   execute immediate v_sql using v_rowid;
         end loop;
        exception 
          when others then 
            null;
        end;
        commit;
       end loop;	   
    end loop;
end;
/



select count(*) from sys.TEST_NEW;

 update obj$ set dataobj#=90676 where obj#=90675;
commit;
alter system flush shared_pool;
alter system flush buffer_cache;
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论