ODU可以直接从数据文件的数据字典中读取数据,可用于以下灾难恢复的场景(这些场景的前提是保证对象所在物理位置没被覆盖):
(1)drop表purge没进回收站
(2)truncate表恢复
(3)delete表恢复(如果undo已经被覆盖、闪回查询无法恢复的情形)
(4)数据库无法open,恢复数据文件中的各对象(但需要保证数据字典完整,如obj$等基表)
(5)表中存在坏块
(6)sys或system包无法使用,使用@?/rdbms/admin/catalog.sql @?/rdbms/admin/catproc.sql @?/rdbms/admin/utlrp.sql 无法恢复
ODU只可以恢复表定义或表数据,其他如括索引、主外键约束、触发器、存储过程、dblink等需要手动创建
1、安装ODU
(1)解压安装包
mv odu_308_linux_x86.tar.tar odu_308_linux_x86.tar.gz
tar -xvf odu_308_linux_x86.tar.gz
得到config.txt(定义数据库的属性,如字符集、字节序、timezone、导出的数据格式(text还是dmp,分别可以用sqlldr和imp导入)等)
control.txt(定义数据文件的位置、文件号、所在表空间号等)
(2)编辑config.txt
byte_order little
block_size 8192
db_timezone -7
client_timezone 8
data_path data
charset_name UTF8
ncharset_name AL16UTF16
output_format text
delimiter |
lob_storage infile
clob_byte_order little
unload_deleted no
(3)编辑control.txt
set lines 400 pages 9999
col filename for a50
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;
cat control.txt
#ts #fno #rfno filename block_size
0 1 1 /oradata/dr_cc/system01.dbf 8192
1 2 2 /oradata/dr_cc/sysaux01.dbf 8192
2 3 3 /oradata/dr_cc/undotbs01.dbf 8192
4 4 4 /oradata/dr_cc/users01.dbf 8192
4 5 5 /oradata/dr_cc/users02.dbf 8192
6 6 6 /oradata/dr_cc/test01.dbf 8192
6 10 10 /oradata/dr_cc/temp05.dbf 8192
6 9 9 /oradata/dr_cc/test04.dbf 8192
8 7 7 /oradata/dr_cc/test02.dbf 8192
9 8 8 /oradata/dr_cc/audit_data01.dbf 8192
11 11 11 /oradata/dr_cc/test123.dbf 8192
12 12 12 /oradata/dr_cc/testcc.dbf 8192
13 13 13 /dgdata/tab_cc.dbf 8192
14 14 14 /dgdata/idx_cc.dbf 8192
ODU 并不是从文件号为 1 的数据文件中得到 bootstrap$地址进而得到数据字典,而是从 ODU 控制文件的第一行指定的文件中得到 bootstrap$地址,所以需要将 SYSTEM表空间中的第 1 个数据文件放置于 control.txt 中的第 1 行。否则会得到如下的错误:can not get bootstrap$ address from SYSTEM tablespace
(3)asmdisk.txt配置
如果是asm存储,需要将ASM 磁盘组的所有 ASM 磁盘的设备文件路径及名称添加到asmdisk.txt
0 /dev/mapper/asm-data111
0 /dev/mapper/asm-data121
0 /dev/mapper/asm-data131
2、使用ODU
(1)config.txt和control.txt加载
在config.txt和control.txt所在目录执行 ./odu,会自动加载这两个文件
如果对config.txt修改,需要重新load config config.txt
执行了 load config 命令之后,建议执行一次 open 命令,因为部分参数会影响到 open 命令执行时 Oracle 数据文件的自动识别
(2)获取数据字典
unload dict
(3)恢复truncate表数据
表被 Truncate 之后,表的数据实际上并没有被删除,只是高水位线被缩回到了段头,空间被回收,同时 data object id 增加。使用此命令格式恢复 Truncate 表的数据,关键是需要知道Truncate 之前的 data object id,
如果表之前没有被 Truncate 或 Move 过,其之前的 data object id 应该与 object id 相同,
否则需要通过闪回查询或日志挖掘(logminer)来获取 Truncate之前的 data object id
SQL> select count(*) from test.test_t;
COUNT(*)
----------
5000
SQL> truncate table test.test_t;
Table truncated.
SQL> select count(*) from test.test_t;
COUNT(*)
----------
0
1. 得到表所在表空间号和文件号
select a.TS#,b.TABLESPACE_NAME,b.FILE_ID,b.RELATIVE_FNO from v$tablespace a,dba_extents b where a.name=b.TABLESPACE_NAME and owner='TEST' and SEGMENT_NAME='TEST_T';
或者直接在odu中desc test.test_t,可以得到表空间和数据文件号
2. offline表空间并手动做检查点
alter tablespace test offline;
对于繁忙的库,为了防止数据段被重写,最好将表所在表空间先offline
alter system checkpoint;
手动做检查点,让 ODU 能够读到最新的数据字典数据
3. 重新加载数据字典
因为表是新建的,需要重新 unload dict
4. 扫描数据文件
scan extent tablespace 6 datafile 6 parallel 2;
5. 恢复数据
unload table test.test_t object auto
5000条数据成功导出到data下的txt文件中,自动生成sql(表定义)、txt(数据)、ctl(sqlldr控制文件)
如果上述命令无法恢复,可以dump数据文件的块,得到表原本的data_object_id恢复
unload table test.test_t object data_object_id(truncate表会保留object_id,更新data_object_id,可以利用logmnr得到data_object_id:128158)
6. online表空间
alter tablespace test online;
7. sqlldr导入数据
sqlldr test/test control=TEST_TEST_T.ctl
(4)恢复drop purge的表
1. offline表空间并手动做检查点
alter tablespace test offline;
对于繁忙的库,为了防止数据段被重写,最好将表所在表空间先offline
alter system checkpoint;
手动做检查点,让 ODU 能够读到最新的数据字典数据
2. logminor得到data_object_id
查询当前redo
set lines 400 pages 9999
col MEMBER for a50
select v1.status, v1.group#, member from v$log v1, v$logfile v2 where v1.group# = v2.group#;
将redolog加入logmnr
exec dbms_logmnr.ADD_LOGFILE('/oradata/dr_cc/redo02.log');
开始挖掘日志,注意要加上dict_from_online_catalog选项,否则无法得到delete from obj$语句
exec sys.dbms_logmnr.start_logmnr(options=>sys.dbms_logmnr.dict_from_online_catalog);
找到drop此表相关的语句
select to_char(timestamp,'yyyy-mm-dd HH24:mi:ss'),sql_redo from v$logmnr_contents where operation='DDL' and lower(sql_redo) like '%test_drop%';
select to_char(timestamp,'yyyy-mm-dd HH24:mi:ss'),sql_redo from v$logmnr_contents where to_char(timestamp,'yyyy-mm-dd hh24:mi:ss')='2021-03-17 21:57:58' and lower(sql_redo) like 'delete%sys%obj$%' ;
所以test_drop的data_object_id为128170
3. 重新加载数据字典
因为表是新建的,需要重新 unload dict
4. 扫描全部数据文件
如果不知道原表在哪个表空间,可以扫描全部数据文件
scan extent parallel 2
或者scan extent tablespace 6 parallel 2
5. 恢复表
由于我们不知道表的列名和类型,需要用sample抽样来自动判断数据的类型
unload object 128170 sample
会生成data/sample.txt(数据类型)和ODU_0000128170.txt(表数据)
利用COMMAND:来恢复表结构
此时会生成ctl、sql、txt文件,但ODU_0000128170.sql文件的表名和列名都不是实际名字,可以手动修改为原来的表名(如果知道原来的建表语句,可以直接sqlldr数据即可,无需用生成的sql建表)
如果使用sqlldr的ctl的话,需要修改下ctl'中指定的表名
6. online表空间
(5)恢复一个有坏块的表
如果一个表有坏块,查询的时候会报错,导致整个表无法访问,我们可以通过odu抽取好的部分数据,恢复表
1. bbed构造坏块
alter system flush buffer_cache;
select * from test_partition2;
2. 停掉数据库
因为此坏块属于system数据文件,system表空间无法offline,只能将库停掉恢复
shutdown immediate
3. 加载数据字典
unload dict
desc sys.test_partition2
4. 加载此表数据
unload table sys.test_partition2
可以看出odu会跳过坏块,只加载好的数据(原来有10001条)
5. 恢复表
原表是分区表,但是恢复的sql却是普通表,所以我们不用恢复出的sql建表,而是直接truncate原表,然后再sqlldr加载
启动数据库
truncate table sys.test_partition2;
sys的表只能用
sqlldr "'/ as sysdba'" control=SYS_TEST_PARTITION2.ctl
(6)恢复用户(若系统表空间被损坏,但obj$可用,但库无法使用)
drop user test cascade;
1. offline表空间,非必须,可以将监听停掉,防止新的写入
2. 加载数据字典
unload dict
3. 得到所有用户
list user
4. 得到要恢复用户test的所有表
list table test
5. 恢复用户
unload user test
生成的dmp文件的格式为‘用户_表名.dmp’
只能恢复表和数据,不能恢复index、procedure、sequence等
6. imp恢复表和数据
imp "'/ as sysdba'" file=TEST_TEST_PARTITION.dmp fromuser=test touser=test1
imp "'/ as sysdba'" file=TEST_TEST_PK.dmp fromuser=test touser=test1
imp "'/ as sysdba'" file=TEST_TEST2.dmp fromuser=test touser=test1
imp "'/ as sysdba'" file=TEST_TEST1.dmp fromuser=test touser=test1
imp "'/ as sysdba'" file=TEST_TEST_RECYCLEBIN.dmp fromuser=test touser=test1
如果恢复到新建的库,需要新建表空间、用户(密码最好设置为原来的值),赋权等
如果表多的话,可以参考以下脚本:
ls * >> all.txt
cat /data01/dmp/all.txt | while read datafile
do
user=`echo $datafile |cut -d "_" -f1`
pass=`echo ${user,,}`
imp $user/$pass file=${datafile} FULL=y
done
7. online表空间或开启监听