Oracle使用fy_recover_data恢复truncate删除的数据

(一)truncate操作概述

在生产中,truncate是使用较多的命令,在使用不当的情况下,往往会造成表的数据全部丢失,恢复较为困难。对于truncate恢复,常见的有以下几种方法可以进行恢复:

  • 使用数据泵导入。该方法操作简单,前提是必须要有备份可用,并且会有数据的丢失;
  • 使用RMAN进行不完全恢复。可将数据库恢复到truncate之前的时刻,但是恢复时间较长;
  • 使用odu、prm-dul、GDUL等收费软件进行恢复;
  • 使用fy_recover_data包;

使用RMAN进行异机恢复已在之前测试过,详见:https://www.cnblogs.com/lijiaman/p/11577001.html

(二)FY_Recover_Data介绍

FY_Recover_Data是国内Oracle ACE大佬黄玮(个人网站:http://www.hellodba.com)开发的一个package,该脚本专门用于对truncate的表进行恢复。

根据作者所述,其原理:如果我们已经有一套元数据及数据块,然后将被TRUNCATE的用户数据块的内容取代其用户数据块的内容,是否可以“骗”过Oracle,让它读出这些数据呢?
回顾一下表扫描的过程,这个方法应该是可行的。我们只要想办法构造出一个结构相同、且具有完整元数据信息和格式化了的用户数据块的傀儡表对象,然后将被TRUNCATE的用户数据块找出,再将其数据内容部分嫁接到傀儡对象的用户数据块,使Oracle以外这是傀儡对象的数据,就能让Oracle扫描并读出数据内容。其原理用图示描述如下:

                                                +-------------------------+  
                                                | Copy Of Dummy Data File |  
                                                |  (With Formmated Blocks)|  
                                                +-------------------------+  
                                                            ||  
                                                            \/  
                                                (Blcok Header,Block Tail)  
                                                            ||  
                                                            \/  
+-------------------+                                +----------------+     Table Scan    +---------------+  
| Source Data File  | => (Data Block Content) =>     |  Dummy Table   |    ============>  | Restore Table |  
|(Without Meta Data)|                                |(With Meta Data)|                   +---------------+  
+-------------------+                                +----------------+


FY_Recover_Data对于表恢复的支持性如下:

压缩表 支持
索引组织表 支持
分区表 支持 
行链接/行迁移 不支持
标准SQL类型 支持
BLOB/CLOB 支持Store in Row
离线恢复 支持
操作系统平台 全部
数据库版本 9i以上
        
本文使用FY_Recover_Data对truncate的几种情况进行恢复测试,以验证fy_recover_data的恢复能力。


(三)操作过程记录

(3.1)使用fy_recover_data包执行truncate恢复,truncate后未有新数据进入表

STEP1:创建测试表,并执行truncate

SQL> create table test01 as select * from dba_objects;

SQLselect count(*)  test01;

  COUNT(*)
----------
     86968

SQL> 
SQLtruncate table test01;

Table truncated

SQL--------
         0

STEP2:导入FY_Recover_Data.pck包

[oracle@source-node ~]$ sqlplus / as sysdba

SQL*Plus: Release 11.2.0.4.0 Production on Tue Apr 21 10:50:17 2020

Copyright (c) 1982,2013,Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Enterprise Edition Release 0 - 64bit Production
With the Partitioning,OLAP,Data Mining and Real Application Testing options

SQL> @/home/oracle/FY_Recover_Data.pck           第一次执行发现第30行存在“&”符号,删除该符号

Enter value for files: 
old  30:    1. Temp Restore and Recover tablespace & files      ---
new   1. Temp Restore and Recover tablespace       ---

Package created.

Warning: Package Body created with compilation errors.

SQL/FY_Recover_Data.pck       删除“&”符号后导入成功

Package created.

Package body created.

STEP3:开始执行恢复,只需要两个参数:schema和table_name

11:20 set time on 43 SQLset serveroutput on 54 SQL> exec fy_recover_data.recover_truncated_table('LIJIAMAN',TEST01'); 12:01: Use existing Directory Name: FY_DATA_DIR 02: Recover : LIJIAMAN.TEST01$ 02: Restore : LIJIAMAN.TEST01$$ 09: Copy file of Recover Tablespace: FY_REC_DATA_COPY.DAT1 09: begin to recover LIJIAMAN.TEST01 existing Directory Name: TMP_HF_DIR 09: Recovering data in datafile /u01/app/oradata/testdb1/users01.dbf 39: 1242 truncated data blocks found. 86968 records recovered in backup LIJIAMAN.TEST01$$ 39: Total: 39: Recovery completed. 39: Data has been recovered LIJIAMAN.TEST01$$ PL/SQL procedure successfully completed.

STEP4:根据恢复日志,会创建临时中转表test01$和test01$$,恢复的数据保存在test01$$中

> show user User is "LIJIAMAN" SQL test01$$; 86968 将数据还原到test01表中 SQLinsert into test01 test01$$; 确认数据已经还原回来 86968

经过测试,如果表被truncate后,未执行其它操作,数据可以使用fy_recover_data恢复回来。


#######################################################################################

(3.2)使用fy_recover_data包执行truncate恢复,truncate后有新数据进入表(新插入的数据比truncate之前多)

STEP1:创建测试表、序列、存储过程

test01 2 ( 3 col1 number,4 col2 5 col3 date,1); font-weight: bold">6 col4 varchar2(30),1); font-weight: bold">7 col5 100) 8 ); created SQL创建自增序列 SQLCREATE SEQUENCE seq01 2 START WITH 1 3 MAXVALUE 99999999 4 MINVALUE 0 CYCLE 6 CACHE 10 7 ORDER; Sequence created SQL创建随机数据插入存储过程,其中col1列单调递增 create or replace procedure p_insert_test01 IS v_col1 NUMBER; BEGIN FOR i IN 1..10000 LOOP select seq01.nextval INTO v_col1 dual; into test01(col1,col2,col3,col4,col5) values (v_col1,(round(dbms_random.value(10000,1); font-weight: bold">100000000)) dual),sysdate,1)">select dbms_random.string(a25) 85) dual)); END LOOP; commitend p_insert_test01;

STEP2:测试表插入10000条数据,col1列的值从1到10000

exec p_insert_test01; PLprocedure successfully completed SQLSELECT MIN(col1),1)">MAX(col1) FROM test01; MIN(COL1) MAX(COL1) -------- ---------- 1 10000

STEP3: 执行truncate操作

Table truncated

STEP4: 接着往表里插入20000条数据

20000-------- ---------- 10001 30000

STEP5:执行恢复操作

14:00:57 on01:06 SQL> 09 SQL13: 13: Recover 14: 18: Copy 18: 18: Recovering data 32: 40220000 records recovered 32: Total: 3232: Data has been recovered STEP6: 通过对test01$$表进行确认,发现返回的数据是truncate之后插入的数据,不符合要求

30000 test01$$; 30000



#######################################################################################

(3.3)使用fy_recover_data包执行truncate恢复,truncate后有新数据进入表(新插入的数据比truncate之前少)

Connected to Oracle 0 
Connected as lijiaman@192.168.10.11testdb1
SQLDROP TABLE  test01 PURGE;

 dropped
SQL3  col1 4  col2   col3 date,1); font-weight: bold">6  col4 7  col5 DROP SEQUENCE seq01;

Sequence dropped
SQL2  START 3  MAXVALUE 4  MINVALUE   CYCLE
  6  CACHE 7  ;

Sequence created
SQLIS
  2  v_col1 ;
  3  BEGIN
  4   LOOP
  5   dual;
  6  values
    (v_col1,1); font-weight: bold">9  (10  sysdate,1); font-weight: bold">11  (12  ( dual));
 13   LOOP;
 14  ;
 15  end p_insert_test01;

16  /

Procedure created

STEP3:执行truncate操作

Table truncated


STEP4:修改存储过程,酶促插入100条数据

100 p_insert_test01; Procedure created 测试表插入100条数据procedure successfully completed

22:34 39 SQL44 SQL52: 52: Recover 57: Copy 57: 57: Recovering data 23:06: 100 records recovered 06: Total: 0606: Data has been recovered STEP6: 通过对test01$$表进行确认,发现返回的数据是truncate之后插入的数据,不符合要求

SQL--------
       1010010100


#######################################################################################
(3.4)测试数据文件被覆盖是否影响恢复

STEP1:创建测试表

testdb1 SQL ) TABLESPACE USERS; Table created

STEP2: 初始时候,表空间总共20MB,剩余15.94MB

SELECT SUBSTR(a.TABLESPACE_NAME,1); font-weight: bold">1,1)">) TablespaceName,1); font-weight: bold">2 round(SUM(a.bytes/10241024),1); font-weight: bold">2) AS "Totle_size(MB)",1); font-weight: bold">3 SUM(NVL(b.free_space11024,1); font-weight: bold">0)),1); font-weight: bold">2) "Free_space(MB)",1); font-weight: bold">4 2)- "Used_space(MB)",1); font-weight: bold">5 ROUND((1024)0))) *100/AS "Used_percent%",1); font-weight: bold">6 SUM((case when a.MAXBYTES = 0 then a.bytes else a.MAXBYTES end)2) "Max_size(MB)",1); font-weight: bold">7 0)))AS "Max_percent" 8 dba_data_files a,1); font-weight: bold">9 (SUM(NVL(bytes,1)">)) free_space1,1); font-weight: bold">10 file_id 11 dba_free_space 12 GROUP BY 13 ) b WHERE a.file_id = b.file_id(+) 15 AND a.TABLESPACE_NAME = USERS' 16 BY a.TABLESPACE_NAME; TABLESPACENAME Totle_size(MB) Free_space(MB) Used_space(MB) Used_percent% Max_size(MB) Max_percent% ------------------------------------------------------------------------------ -------------- -------------- -------------- ------------- ------------ ------------ USERS 20 15.94 4.06 20.31 20 20.31

STEP3:test01表插入大量数据

> PL/ begin p_insert_test01; ; ORA-01653: unable to extend table LIJIAMAN.TEST01 by 128 tablespace USERS ORA06512: at "LIJIAMAN.P_INSERT_TEST01",line 6 ORA06512: at line 1

STEP4:此时,表空间总共20MB,剩余0.94MB

20 0.94 19.06 95.31 95.31

STEP5:此时test01表有90000行数据

90000-------- ---------- 109751 199750

STEP6:对test01执行truncate

STEP7:执行truncate后,空间已经释放

15.88 4.12 20.63 20.63

STEP8:创建表test02,用来覆盖test01释放的空间

table test02 dba_objects; STEP9:test02表创建之后,剩余空间为5.88MB,可以说明:test02表的数据占用了test01表释放出来的空间,即test01表的部分数据已经被覆盖

5.88 14.12 70.63 70.63

STEP10:执行恢复操作

15:09:58 05 SQL10 SQL17: 17: Recover 22: Copy 22: 22: Recovering data 31: 64524439 records recovered 31: Total: 3131: Data has been recovered STEP11: 发现只恢复了部分数据,不符合要求

truncate之前test01表有90000行数据,恢复了24339行数据 24439-------- ---------- 199750


(四)总结

对于使用工具fy_recover_data进行数据恢复,需要确保:

①truncate之后,需要保证没有新的数据进入表中,否则无法还原;

②存放该表的数据文件块不能被覆盖,否则无法完整还原数据。

在发生故障后,可以迅速使用:

alter tablespace users read only; SQLread write;

来关闭/开启表空间的写功能,这样可以保证数据文件不会被覆写。


【完】

     Copyright © 2020 ruiliair. All Rights Reserved.

相关文章

文章浏览阅读773次,点赞6次,收藏9次。【代码】c# json字符...
文章浏览阅读8.7k次,点赞2次,收藏17次。此现象一般定位到远...
文章浏览阅读2.8k次。mysql脚本转化为oracle脚本_mysql建表语...
文章浏览阅读2.2k次。cx_Oracle报错:cx_Oracle DatabaseErr...
文章浏览阅读1.1k次,点赞38次,收藏35次。本文深入探讨了Or...
文章浏览阅读1.5k次。默认自动收集统计信息的时间为晚上10点...