实战,Oracle数据库从dbf文件还原表、存储过程等信息

       首先讲讲此篇文章成型的背景,本人有一台测试服务器,主要从事生产库部署前的数据配置及存储过程编写,因为是测试服务器,所以没有严格的执行备份,年初备份过一次,其他零零散散存了些创建表的sql和测试数据,大部分近期的成果都在测试数据库,暂命名为T库(文后都以此代指)。

       基于安全考虑,年初将数据库升级到了11.2.0.4,此数据库漏洞相对较少,这也是为何年初备份的原因,从以下下载地址获取的安装文件。

11gR2 11.2.0.4:
Linux x86:
https://updates.oracle.com/Orion/Services/download/p13390677_112040_LINUX_1of7.zip?aru=16720989&patch_file=p13390677_112040_LINUX_1of7.zip
https://updates.oracle.com/Orion/Services/download/p13390677_112040_LINUX_2of7.zip?aru=16720989&patch_file=p13390677_112040_LINUX_2of7.zip

Linux x86-x64:
https://updates.oracle.com/Orion/Services/download/p13390677_112040_Linux-x86-64_1of7.zip?aru=16716375&patch_file=p13390677_112040_Linux-x86-64_1of7.zip
https://updates.oracle.com/Orion/Services/download/p13390677_112040_Linux-x86-64_2of7.zip?aru=16716375&patch_file=p13390677_112040_Linux-x86-64_2of7.zip

Windows x86:
https://updates.oracle.com/Orion/Services/download/p13390677_112040_WINNT_1of6.zip?aru=16919969&patch_file=p13390677_112040_WINNT_1of6.zip
https://updates.oracle.com/Orion/Services/download/p13390677_112040_WINNT_2of6.zip?aru=16919969&patch_file=p13390677_112040_WINNT_2of6.zip

Windows x86-x64:
https://updates.oracle.com/Orion/Services/download/p13390677_112040_MSWIN-x86-64_1of7.zip?aru=16908159&patch_file=p13390677_112040_MSWIN-x86-64_1of7.zip
https://updates.oracle.com/Orion/Services/download/p13390677_112040_MSWIN-x86-64_2of7.zip?aru=16908159&patch_file=p13390677_112040_MSWIN-x86-64_2of7.zip 

从以上域名可以看出,应该是oracle官网的服务器直接下载的,但是在最近的一次重启服务器之后,数据库直接无法启动,报ORA-600 16703错误,以下两篇文章已经有详细的阐述,在此严重怀疑这是Oracle的官方行为。我尝试过linux版本的oracle11gR2 11.2.0.4也有此问题

警告:互联网中有oracle介质被注入恶意程序导致—ORA-600 16703

案发现场:被注入的软件及 ORA-600 16703 灾难的恢复

知道问题所在就考虑如何将数据恢复。

  • 二、还原环境搭建

       在搭建数据库还原环境过程中走了很多弯路,参照以上恢复方法,首先选择从bbed恢复,通过操作block的方式,直接修复system01.dbf,这样系统不需要做任何修改就能恢复。最终以失败告终,原因无非是bbed复杂的操作逻辑、脚本编写学习成本太高,linux环境搭建及数据库创建花费过多时间(装linux虚拟机及oracle环境,计划耗费了1周的时间)。期间也用过linux环境下的mydul(tomcoding编写,无导出大小限制),此软件运行时会分析system01.dbf的完整性,所以最终没有成功。

      再次梳理思路,明确自己的需求:

  1. 测试数据库,不需要将整库还原。
  2. 最好在windows平台下,不用重新搭建数据库环境。
  3. 只要导出需要还原的表、存储过程、功能、视图即可。

经过n次测试,最后采用了以下组合,收集这些工具也花费了几天时间

1)windows环境(需要有oracle客户端或服务器,需要用到sqlldr命令)

2)一台可以存放还原数据的目标oracle数据库B库(此处命名为B库以下代指)

3)诗檀 PRM-DUL社区版软件,3.1、4.1均可,5.1测试会有中文乱码的情况

4)oracle官方的odu软件

5)aul6软件

6)plsql,Navicat类似的数据库连接软件

相关软件可以在此处下载:Oracle从dbf恢复数据需要的软件

  • 三、操作过程

主要参考:

利用AUL工具恢复oracle dbf文件中的数据

oracle中truncate table后的数据使用odu恢复模拟

基于Oracle 数据文件DBF恢复数据

数据库恢复的整体思路是在现有已备份的数据库的基础上进行还原。生产库基本上每天都会备份。测试库备份的没有那么频繁,所以只需要把近期更改的东西还原回来就可以了,一般就是一些表的配置数据,功能方法,存储过程,试图等由于windows的系统比较强大友好的资源管理系统,所以在windows之下执行恢复是最好的选择。

  • prm-dul 导出blob clob,1万行以内都可以,比较直观的验证数据集结果。
  • aul6这款软件配置比较简单,可以与odu进行配合使用,但是没法导出CLOB和blob字段,且在导出存储过程的过程中有些数据丢失了。
  • odu这款软件相当于aul6,配置稍微麻烦一些,需要查出对应表空间所在的逻辑位置(在aul6可以直接呈现出来,直接借用即可),这个软件导出的数据比较全,但是aul6有相同的缺点,就是不能导出clob,blob字段(sqlldr导入数据貌似也不支持blob,clob)。

所以数据恢复以aul6为主,odu做配合,prm-dul做辅助及验证。
      下面就以导出sys.source$,sys.obj$,sys.user$,然后还原整个存储过程作为例子。其他用户表的导出方法可以如法炮制。

第一步。由于我的sys.tab$已经被删掉,所以用Aul6直接操作的时候无法导出tab$表,但是根据上面文章对数据库灾难的详细阐述。可以确定,数据库tab$删除前备份的那张表应该是最新的一个object对象,用prm-dul直接找到最后一个object,与现在正常的数据库的表结构进行对比,正好验证了我的想法,与正常数据库的tab$表完全一致,但是prm-dul社区版只能导出1万条数据,一般如果整个库的用户不超过20个,且总表的数量不是很多,1万条数据足够,我的恰巧是8000多条。先用数据搭桥的方式把obj117470这张表导入B库(注意,prm-dul导出unkown字段类型时,可能会存在编码错误,这个再数据搭桥的审核,可以选择目标库的列类型,放置数据转码错误)

然后操作AUL6,参照AUL6的使用方法,首先配置好cfg,名字就叫1.cfg吧,内容如下

0   0   E:\backup\oradata\zjgl\SYSTEM01.DBF

右键以管理员方式运行aul6_final.exe,会进入操作界面,执行以下操作,获得到我们需要的配置文件

AUL>open 1.cfg
AUL>unload table user$;
AUL>unload table obj$;
AUL>unload table tab$;
AUL>unload table col$;

第一行的open 1.cfg很关键,回显的内容再odu的配置中用得到。

得到如下四个配置文件,但是很明显我的AULTAB.TXT是0KB

从正常的数据库还原出的AULTAB.TXT对应的字段分别为obj#、dataobj#、ts#、file#、block#、tab#,对应的obj117470表的字段分别为col1、col2、col3、col4、col5、col7,所以执行以下sql,就可以查出自己需要手动构建的AULTAB.TXT的信息

SELECT col1||','||col2||','||col3||','||col4||','||col5||','||col7||',' FROM obj117470;

把查询的数据粘贴进AULTAB.TXT即可。

这样我们所有aul6的基本准备工作就已经完成了。

第二步、还原原来的资源相关的数据,分别执行以下

AUL>UNLOAD TABLE sys.obj$ TO obj$.txt;
AUL>UNLOAD TABLE sys.user$ TO user$.txt;
AUL>UNLOAD TABLE sys.source$ TO source$.txt;

 

可以看到source的条数只有101万条左右(后来对比导出的数据,发现这个表缺了30多万条数据)

以obj$举例,obj$.txt为存放的数据,OBJ__sqlldr.ctl为导入数据时用的控制文件,OBJ__syntax.sql为数据表的创建文件,所以先创建表,我将所有需要还原的表都变更为T_开头、试图被更为TV_开头的样式,这样后期方便区分,也不与原来的表及试图冲突

创建目标表t_obj,t_user,t_source,tv_current_edition_obj,tv_source的sql如下,最终只需要再tv_source查询我们需要的存储过程或功能方法即可。

create table T_USER
(
  user#        NUMBER not null,
  name         VARCHAR2(30) not null,
  type#        NUMBER not null,
  password     VARCHAR2(30),
  datats#      NUMBER not null,
  tempts#      NUMBER not null,
  ctime        DATE not null,
  ptime        DATE,
  exptime      DATE,
  ltime        DATE,
  resource$    NUMBER not null,
  audit$       VARCHAR2(38),
  defrole      NUMBER not null,
  defgrp#      NUMBER,
  defgrp_seq#  NUMBER,
  astatus      NUMBER not null,
  lcount       NUMBER not null,
  defschclass  VARCHAR2(30),
  ext_username VARCHAR2(4000),
  spare1       NUMBER,
  spare2       NUMBER,
  spare3       NUMBER,
  spare4       VARCHAR2(1000),
  spare5       VARCHAR2(1000),
  spare6       DATE
);

create table T_OBJ
(
  obj#        NUMBER not null,
  dataobj#    NUMBER,
  owner#      NUMBER not null,
  name        VARCHAR2(30) not null,
  namespace   NUMBER not null,
  subname     VARCHAR2(30),
  type#       NUMBER not null,
  ctime       DATE not null,
  mtime       DATE not null,
  stime       DATE not null,
  status      NUMBER not null,
  remoteowner VARCHAR2(30),
  linkname    VARCHAR2(128),
  flags       NUMBER,
  oid$        RAW(16),
  spare1      NUMBER,
  spare2      NUMBER,
  spare3      NUMBER,
  spare4      VARCHAR2(1000),
  spare5      VARCHAR2(1000),
  spare6      DATE
);

create table T_SOURCE
(
  obj#   NUMBER not null,
  line   NUMBER not null,
  source VARCHAR2(4000)
);

create or replace view tv_current_edition_obj as
select o."OBJ#",
       o."DATAOBJ#",
       o."OWNER#",
       o."NAME",
       o."NAMESPACE",
       o."SUBNAME",
       o."TYPE#",
       o."CTIME",
       o."MTIME",
       o."STIME",
       o."STATUS",
       o."REMOTEOWNER",
       o."LINKNAME",
       o."FLAGS",
       o."OID$",
       o."SPARE1",
       o."SPARE2",
       o."SPARE3",
       o."SPARE4",
       o."SPARE5",
       o."SPARE6",
       (case
           when (o.type# not in (4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 22, 87) or
                bitand(u.spare1, 16) = 0) then
            null
           when (u.type# = 2) then
            (select eo.name from t_obj eo where eo.obj# = u.spare2)
           else
            'ORA$BASE'
       end) AS bz
  from t_obj o, t_user u
 where o.owner# = u.user#;

CREATE OR REPLACE VIEW TV_SOURCE AS
select (SELECT NAME FROM t_user WHERE  user#=o.owner#) AS owner,o.name,
decode(o.type#, 7, 'PROCEDURE', 8, 'FUNCTION', 9, 'PACKAGE',
               11, 'PACKAGE BODY', 12, 'TRIGGER', 13, 'TYPE', 14, 'TYPE BODY',
               22, 'LIBRARY', 87, 'ASSEMBLY', 'UNDEFINED') AS TYPE,
s.line, s.source
from tv_CURRENT_EDITION_OBJ o, t_source s
where o.obj# = s.obj#
  and ( o.type# in (7, 8, 9, 11, 12, 14, 22) OR
       ( o.type# = 13 AND o.subname is null));

当然所有的.ctl文件也都需要修改,因为我们需要还原的目标表的表名变了,还是拿obj$着张表举例,那么OBJ__sqlldr.ctl需要修改

打开cmd,执行导入,当然前提条件时你的当前的操作系统已经装好了oracle相关运行环境,能进行sqlldr操作。

操作cmd定位到你的aul6的运行目录,然后执行以下操作

sqlldr B/B@orcl control=OBJ__sqlldr.ctl

上面的B/B@orcl分别代之的目标库的用户名密码及连接串。其他的source$,user$也如obj$操作,此处不再赘述。

需要强调一下:

由于存储过程很多字符连接用到了双竖线“||”,而恰巧sqlldr的本地txt存储文件,也是以“|”作为字段间的分割符,所以需要先转置一下样式,我是先将txt中的“||”全部替换为“^^”,导入完毕之后,在replace回来(UPDATE t_source SET SOURCE=REPLACE(SOURCE,'^^','||');)

第三步、前面已经说明了,aul6导出的存储过程的数据并不完整,所以我们需要用odu进行数据补充

首先要配置好control.txt,其实与aul6的1.cfg配置差不多,但是要查出dbf文件的#ts、 #fno、  #rfno 值,通过前面执行open 1.cfg,我们已经获得了#ts #fno(#fno、#rfno值相同),所以可以手动构建出control.txt的结构

#ts #fno   #rfno     filename                                          block_size
0     1      1        E:\backup\oradata\zjgl\SYSTEM01.DBF                8192 

右键以管理员身份运行odu.exe即可,然后分别执行一下操作

ODU>unload dict
ODU>scan extent

之前也提过,odu操作不是很方便,只是辅助查询用的,我们现在时source$这张表的数据不全,所以只需要把source$这张表导出即可,odu需要查出每张表的object值才可导出,咱们直接到B库中aul6导出的t_obj这张表中查询,查得为224(如果这张表再多个用户下,还需要搭配t_user这张表进行查询)

然后执行以下操作,将source$的数据导出

ODU> unload table sys.source$ object 224

此时导出的又130多万条数据。

再data文件夹下会生成三个文件

这三个文件与aul6导出的文件相似,由于咱们已经创建了t_source这张表,所以只需要把控制文件.ctl的目标表名改一下就可以了,这里不再赘述。然后用sqlldr导入,代码如下

sqlldr B/B@orcl control=ODU_0000000224.ctl

当然,数据文件中也会有双竖线无法导入的问题,处理方式与前面一样,将双竖线进行替换导入,然后在replace回来就行了。

经过以上操作,基本上我们执行tv_source的查询就会得到我们想要的数据了,与执行select * from user_source的结构基本一致

第四步、简单介绍以下如何把含有clob,blob字段的数据表导出,这里用的时prm_dul,一般含有这样字段的表大部分是资源表或配置表,如果业务量不大的话,大部分不会超过1万行,所以用prm_dul即可,尝试过用aul6导出的所有数据为空,odu除了clob,blob,其他字段都能导出,只有prm_dul可以顺利导出。

首先还是查询我们的t_obj表,定位到我们需要到出表的obj#值(查询出多个的话,需要配合列owner#与t_user表的关联查询筛选用户)。

参考打开prm_dul的教程,依据咱们找到obj#值,可以快速定位到需要导出的

四、总结

按照以上操作,基本上可以还原回已丢失的数据,相对于bbed直接操作block,直接可以让瘫痪的数据库再次启动,这种方法操作相对复杂一些,但是好在学习成本很低,按部就班操作80%的情况可以恢复数据,我恢复的数据库为oracle11g 11.2.0.4非ASM版其他版本没有尝试过,也有可能无法恢复,有兴趣的可以参照恢复一下

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值