震惊,一单几十个W的Oracle非常规恢复,原来这么简单?

前言:

震惊,我也不知道为什么要震惊,现在写公众号好像不“震惊”不太行了,Oracle非常规恢复极其复杂,需要非常扎实的功底,精通底层块结构、数据库原理等,我也是初学者,曾经用bbed工具修复过几次故障,很多细节仍然不是完全明白,但是如果使用恢复工具操作会简单很多,常见的有DUL、ODU等,今天简单介绍下如何使用ODU工具恢复误删除的数据,分为三种误操作类型,分别是TRUNCATE、DELETE、DROP。

说明:

文章整理自2017-12-29我在ITPUB博客发布的以下文章:

Oracle Delete表恢复(ODU)

    https://blog.itpub.net/29785807/viewspace-2149488/

    Oracle Truncate表恢复 (ODU)

      https://blog.itpub.net/29785807/viewspace-2149477/

      Oracle Drop表(purge)恢复(ODU)

        https://blog.itpub.net/29785807/viewspace-2149476/

        测试库版本:11.2.0.1.0

        ODU工具版本:3.0.9

        注意:文章发布时间较久,可能存在错误,仅供参考,请勿用于生产环境。

        下面让我们一起看下这三种误操作如何恢复吧。

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

        一:表中数据被误TRUNCATE

        生成测试数据

          create table tt1 as select * from dba_objects;
          create table tt2 as select * from tt1;
          select * from dba_objects where object_name='TT1'; ---OBJECT_ID 87295 ---DATA_OBJECT_ID 87295
          ---object_id: Dictionary object number of the object.
          ---Data_object_id: Dictionary object number of the segment that contains the object.

          模拟误删除

            truncate table tt1;
            select *from tt1;

            使用ODU进行恢复

            步骤如下:

              (1) OFFLINE表所在的表空间
              (2) 生成数据字典:unload dict
              (3) 扫描数据:scan extent
              (4) 恢复表:unload table username.tablename object auto

              1:OFFLINE表所在的表空间

                select * from dba_objects where object_name='TT1'; ---OBJECT_ID 87290 ---DATA_OBJECT_ID 87297
                select tablespace_name from user_tables where table_name='T1'; ---USERS
                alter tablespace USERS offline;
                alter system checkpoint;

                2:ODU 版本 3.0.9

                3:生成数据字典

                4:扫描数据

                5:恢复表

                自动生成以下三个文件

                6:通过 sqlldr 加载数据到数据库

                7:验证数据

                  select count(*) from tt1; ---86155
                  select * from tt1;

                  ......

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

                  二:表中数据被误DELETE

                  创建测试数据

                    create table t0 as select * from dba_objects;
                    create table t0_bak as select * from t0;
                    select count(*) from t0; ---86159

                    模拟误删除

                      delete t0 where object_id>85000; commit;
                      select count(*) from t0; ---84141

                      如果无有效备份,也无法闪回,如何恢复

                      使用ODU工具进行恢复

                      1.:将参数 unload_deleted 设置为 YES

                      2.:生成数据字典

                      3:恢复表

                        rename t0 to tt0;
                        CREATE TABLE "CHEN"."T0"
                        (
                        "OWNER" VARCHAR2(30) ,
                        "OBJECT_NAME" VARCHAR2(128) ,
                        "SUBOBJECT_NAME" VARCHAR2(30) ,
                        "OBJECT_ID" NUMBER ,
                        "DATA_OBJECT_ID" NUMBER ,
                        "OBJECT_TYPE" VARCHAR2(19) ,
                        "CREATED" DATE ,
                        "LAST_DDL_TIME" DATE ,
                        "TIMESTAMP" VARCHAR2(19) ,
                        "STATUS" VARCHAR2(7) ,
                        "TEMPORARY" VARCHAR2(1) ,
                        "GENERATED" VARCHAR2(1) ,
                        "SECONDARY" VARCHAR2(1) ,
                        "NAMESPACE" NUMBER ,
                        "EDITION_NAME" VARCHAR2(30)
                        );

                        4:通过 sqlldr 将数据加载到数据库

                        5 :验证数据

                          select count(*) from t0; ---86159
                          select * from t0 where object_id>85000;

                          ......

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

                          三:表中数据被误DROP

                          通过 ODU 恢复 drop 掉的表 (purge) 基本步骤如下

                            1:offline表所在表空间;
                            2:通过 logminer 挖出被 drop 表对应 object_id ;
                            3:使用 ODU 工具将表数据抽到文件中;
                            4:使用 sqlldr 将数据加载到数据库;
                            5:验证;

                            准备测试数据                

                            1 创建测试表 odu_test

                              create table odu_test (a number,b varchar2(10),c nvarchar2(30),d varchar2(20),e date,f timestamp,g binary_float,h binary_double);

                              2 插入测试数据

                                insert into odu_test
                                select rownum,
                                lpad('x', 10),
                                'NC测试 ' || rownum,
                                'ZHS测试 ' || rownum,
                                sysdate + dbms_random.value(0, 100),
                                systimestamp + dbms_random.value(0, 100),
                                rownum + dbms_random.value(0, 10000),
                                rownum + dbms_random.value(0, 10000)
                                from dba_objects
                                where rownum exec sys.dbms_logmnr.start_logmnr(options=>sys.dbms_logmnr.dict_from_online_catalog);
                                SQL> select scn,timestamp,sql_redo from v$logmnr_contents where operation='DDL' and sql_redo like '%odu_test%' order by 2 ;
                                ......
                                990001 2017/12/27 drop table odu_test purge;
                                SQL> select scn,timestamp,sql_redo from v$logmnr_contents where timestamp=to_date('2017-12-27','yyyy-mm-dd') order by 1;
                                SQL> create table logmnr_1 as (select * from v$logmnr_contents;
                                SQL> exec sys.dbms_logmnr.end_logmnr;
                                select *from sys.logmnr_1 where scn='990001'; ---DATA_OB# 87270
                                select * from sys.logmnr_1 where *operation='DDL' and*/ LOWER(sql_redo) like '%odu_test%' order by 2 ;
                                /*
                                delete from "SYS"."OBJ$" where "OBJ#" = '87270' and "DATAOBJ#" = '87270' and "OWNER#" = '84' and "NAME" = 'ODU_TEST' and "NAMESPACE" = '1' and "SUBNAME" IS NULL and "TYPE#" = '2' and "CTIME" = TO_DATE('27-12 月 -17', 'DD-MON-RR') and "MTIME" = TO_DATE('27-12 月 -17', 'DD-MON-RR') and "STIME" = TO_DATE('27-12 月 -17', 'DD-MON-RR') and "STATUS" = '1' and "REMOTEOWNER" IS NULL and "LINKNAME" IS NULL and "FLAGS" = '0' and "OID$" IS NULL and "SPARE1" = '6' and "SPARE2" = '1' and "SPARE3" = '84' and "SPARE4" IS NULL and "SPARE5" IS NULL and "SPARE6" IS NULL and ROWID = 'AAAAASAABAAAVKkABB';
                                */

                                (3)修改原 control.txt 文件

                                  select d.TS# ts,
                                  d.FILE# fno,
                                  d.FILE# fno,
                                  d.NAME filename,
                                  d.BLOCK_SIZE block_size
                                  from v$datafile d
                                  order by ts;
                                  0 1 1 D:APPADMINISTRATORORADATACJCSYSTEM01.DBF 8192
                                  1 2 2 D:APPADMINISTRATORORADATACJCSYSAUX01.DBF 8192
                                  2 3 3 D:APPADMINISTRATORORADATACJCUNDOTBS01.DBF 8192
                                  4 4 4 D:APPADMINISTRATORORADATACJCUSERS01.DBF 8192
                                  ---control.txt

                                  (4) 登录odu

                                  (5)扫描数据

                                  ---企业版 ODU 需要授权

                                  ---本次实验使用测试版 ODU

                                  (6) 恢复表

                                  生成创建表的语句和控制文件

                                  这个命令生成了如下文件

                                    ODU_0000087270.ctl 和 ODU_0000087270.sql
                                    CREATE TABLE "ODU_0000087270"
                                    (
                                    "C0001" NUMBER ,
                                    "C0002" VARCHAR2(4000) ,
                                    "C0003" NVARCHAR2(2000) ,
                                    "C0004" VARCHAR2(4000) ,
                                    "C0005" DATE ,
                                    "C0006" DATE ,
                                    "C0007" BINARY_FLOAT ,
                                    "C0008" BINARY_DOUBLE
                                    );

                                    (7) online 表空间

                                      alter tablespace users online;

                                      (8) 通过 sqlldr 加载数据

                                      (9) 验证数据

                                        select count(*) from ODU_0000087270; ---10000

                                        查看恢复后表数据

                                          select * from ODU_0000087270;

                                          ......

                                          ###chenjuchao 20240410###

                                          欢迎关注我的公众号《IT小Chen》,后面计划学习并更新一些bbed工具的使用场景,尝试使用bbed恢复数据。