震惊,一单几十个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恢复数据。