How to recover data with DUL after table dropped

on

首先系统情况如下:
1. Oracle版本是9.2.0.8,操作系统是IBM AIX
2. 数据文件存储在裸设备上
3. 被删除的表是分区表
4. 数据库非归档,没有任何备份
5. 在误drop table以后,立刻将包含该表的表空间offline了,并且保留了当时的current online redo文件
6. 保留了之前建表时的create脚本

恢复过程如下:
1. DUL使用的init.dul内容:

osd_big_endian_flag=true
osd_dba_file_bits=10
osd_c_struct_alignment=32
osd_file_leader_size=1
osd_word_size=32

control_file=/tmp/control.dul
db_block_size=8192
compatible=9

2. DUL使用的control.dul文件内容

58 58 /somepath/rawdevice1 4096 blocks 4095873
58 110 /somepath/rawdevice2 4096 blocks 639873
58 126 /somepath/rawdevice3 4096 blocks 255873

第1位是TS#,第2位是RFILE#,第3位是数据文件全路径,第4位是在AIX系统中裸设备需要跳过的字节,第5位是数据文件的真实block数(从v$datafile中以size/db_block_size获得)。

第4,5两位在数据文件为裸设备的情况下才需要,否则在scan database时扫描到裸设备结尾的时候,将可能报错。

3. 通过logminer得到被drop掉的表分区的data object id(因为被drop了,因此无法从system数据字典中获得)。如何使用Logminer不在本文范围内。
比如最后看到SQL_REDO字段的结果是类似于这样的输出:

delete from "SYS"."OBJ$" where "OBJ#" = '25514' and "DATAOBJ#" = '25514' ......

那么就可以知道data object id = 25514

4. 登录DUL

DUL> scan database;
DUL> unload table table_name partition(p_name) 
(col_name1 VARCHAR2(6),col_name2 VARCHAR2(17),col_name3 VARCHAR2(3).....) 
storage (dataobjno 25514);

这里的table_name和p_name其实都可以随便写,甚至不写partition也可以,最主要的是dataobjno必须正确,就可以unload出表数据。当然还必须有表结构,否则会报告无法在OBJ$中找到相应表。

如果此处没有事先保留的create table脚本,而且也不知道表中有哪些字段,那么工作量就大了。
基本步骤如下:

DUL> alter session set use_scanned_extent_map = true;
DUL> scan database;
DUL> scan tables;

然后在dul.log中查找上面的data object id,找到的话,将会是类似于下面的输出:

UNLOAD TABLE OBJNO25514 ( COL001 VARCHAR2(6), COL002 VARCHAR2(17), COL003 VARCHAR2(3)
        , COL004 VARCHAR2(26), COL005 VARCHAR2(30), COL006 NUMBER, COL007 NUMBER
        , COL008 VARCHAR2(1), COL009 NUMBER, COL010 VARCHAR2(38) )
    STORAGE( DATAOBJNO 25514 );

同时为了保险起见,在scan tables的过程中,DUL在log中还显示了该表的前5行记录内容,可以比对一下看看是否确实是被误删除的表。

之后,就是根据对于业务的了解,重新构建表结构了,其实对于只是删除了一张表而言,工作量还可以接受,但是如果是删除了整个USER …

5. 之后就是用sqlldr重新加载数据的事情了,不再赘述。

DUL格言是:Life without DUL

错误时刻都可能发生,为了数据的安全,为了自己工作饭碗的安全,还是做好备份吧。

12 Comments Add yours

  1. anysql says:

    刚用MyLOG+AUL恢复了一个这样的案例。

  2. kamus says:

    @anysql
    把MyLOG和AUL开源吧 >:) >:)

  3. overmars says:

    被误删除的表是创建在ASSM的表空间上面吗?
    alter session set use_scanned_extent_map = true;的作用是什么?

  4. boypoo says:

    用 DUL和AUL 的过程都很痛苦

  5. boypoo says:

    kamus,你的头像怎么加进去的?

  6. Kamus says:

    @overmars
    在本例中不是ASSM
    作用是在没有数据字典的时候,告诉DUL用每个block自己头部的object id作为unload table的基础。

  7. Kamus says:

    boypoo :
    用 DUL和AUL 的过程都很痛苦

    那尝试用一下老熊的ODU吧,呵呵

  8. anysql says:

    刚看了一下ODU, 命令语法和AUL差不多啊.

  9. Kamus says:

    @anysql
    都是一样的unload数据方法,自然命令语法都差不多吧。
    我看了一下耿永辉的gDUL,语法也差不多。
    你们几个干脆一起做这个产品吧,何苦各自为营,劳动力浪费啊。

  10. anysql says:

    除了直接访问ASM没搞定外,其他的都一个人搞定了,所以没想open source.

  11. kamus says:

    open source也不是为了解决自己一个人搞不定的技术难题。其实。。。open source是一种生活方式,呵呵。

Leave a Reply to Kamus Cancel reply

Your email address will not be published. Required fields are marked *