oracle数据库灾难挽救应急方案之DML误操作恢复

1核心业务表误delete恢复

1.1模拟delete误操作

创建jason业务表,如下:

SQL> create table jason as select * from dba_objects;
SQL> create index idx_jason_oid on jason(object_id);

删除jason业务表部分数据,在提交之后,发现部分数据存在误删,如下:

SQL> delete from jason where object_id between 3000 and 6000;
3001 rows deleted.

1.2闪回查询恢复误删数据

首先,检查当前时间和undo保留时间,如下:

SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
SQL> select sysdate from dual;
SYSDATE
-------------------
2022-05-06 23:29:07
SQL> show parameter undo_retention
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
undo_retention                       integer     900

根据时间戳执行闪回查询,检查数据能否被找回,如下:

SQL> select count(*) from sys.jason as of timestamp to_timestamp('2022-05-06 23:14:07','yyyy-mm-dd hh24:mi:ss') where object_id between 3000 and 6000;
  COUNT(*)
----------
      3001

如果数据确认可以被找回来,立即将undo中前镜像数据插回至jason业务表,如下:

SQL> insert into jason select * from sys.jason as of timestamp to_timestamp('2022-05-06 23:14:07','yyyy-mm-dd hh24:mi:ss') where object_id between 3000 and 6000;
3001 rows created.

如果数据无法通过undo闪回查询找到,则尝试1.1.3节方案进行数据挽救。

SQL> select count(*) from sys.jason as of timestamp to_timestamp('2022-05-06 23:14:07','yyyy-mm-dd hh24:mi:ss') where object_id between 3000 and 6000;
ERROR at line 1:
ORA-01555: snapshot too old: rollback segment number 7 with name
"_SYSSMU7_2329891355$" too small

1.3归档日志挖掘恢复误删数据

检查数据库全局force_logging和supplemental_log_data_min特性是否开启,如下:

SQL> select name,open_mode,log_mode,force_logging,supplemental_log_data_min from v$database;
NAME      OPEN_MODE            LOG_MODE     FORCE_LOGGING   SUPPLEMENTAL_LOG_DATA_MIN
--------- -------------------- ------------ --------------- -------------------------
TESTDB19  READ WRITE           ARCHIVELOG   NO              NO

手动切换归档日志,并记录当前时间,如下:

SQL> alter system switch logfile;
SQL> select sysdate from dual;
SYSDATE
-------------------
2022-05-06 23:58:35

检查数据误删除期间产生的归档日志文件,如下:

select unique NAME, THREAD#, SEQUENCE#, COMPLETION_TIME
  from gv$archived_log
 where thread# = 1
   and COMPLETION_TIME >=
       to_date('2022-05-07 03:09:24', 'yyyy-mm-dd hh24:mi:ss')
   and COMPLETION_TIME <=
       to_date('2022-05-07 03:11:19', 'yyyy-mm-dd hh24:mi:ss')
 order by SEQUENCE#;

添加第一个要加载的归档日志文件,如下:

SQL> execute dbms_logmnr.add_logfile(logfilename=>'/oracle/app/fast_recovery_area/TESTDB19C/archivelog/2022_05_07/o1_mf_1_134_k7d6w2g6_.arc',options=>dbms_logmnr.new);

多次添加要加载的归档日志文件,如下:

SQL> execute dbms_logmnr.add_logfile(logfilename=>'/oracle/app/fast_recovery_area/TESTDB19C/archivelog/2022_05_07/o1_mf_1_135_k7d6wo28_.arc',options=>dbms_logmnr.addfile);

执行日志挖掘分析,如下:

SQL> execute dbms_logmnr.start_logmnr(options=>dbms_logmnr.dict_from_online_catalog);

查询v$logmnr_contents动态性能视图,获取归档日志解析信息,如下:

SQL> select count(*) from v$logmnr_contents;
  COUNT(*)
----------
    391721
SQL> create table sys.hzmc_logmnr_contents as select * from v$logmnr_contents;

关闭日志挖掘分析,如下:

SQL> execute dbms_logmnr.end_logmnr;

将误删除操作的反向插入语句输出至jason_insert.sql,如下:

SQL> set lines 1000 pages 0
SQL> spool jason_insert.sql
SQL> select sql_undo from sys.hzmc_logmnr_contents where OPERATION='DELETE' and sql_redo like '%JASON%';
SQL> spool off

清理jason_insert.sql文本中的首行和尾行,如下:

shell> vi jason_insert.sql

将反向解析出来的SQL语句插回至jason业务表,如下:

SQL> @jason_insert.sql

2、核心业务表误update恢复

2.1模拟update误操作

创建jason业务表,如下:

SQL> create table jason as select * from dba_objects;
SQL> create index idx_jason_oid on jason(object_id);

更新jason业务表部分数据,在提交之后,发现部分数据存在误更新,如下:

SQL> update jason set object_id=1 where object_id<=70000;
69346 rows updated.
SQL> commit;

2.2闪回查询恢复误删数据

首先,检查当前时间和undo保留时间,如下:

SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
SQL> select sysdate from dual;
SYSDATE
-------------------
2022-05-07 06:13:38
SQL> show parameter undo_retention
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
undo_retention                       integer     900

根据时间戳执行闪回查询,检查数据能否被找回,如下:

SQL> select count(*) from sys.jason as of timestamp to_timestamp('2022-05-07 06:12:38','yyyy-mm-dd hh24:mi:ss') where object_id<=70000;
  COUNT(*)
----------
     69346

如果数据确认可以被找回来,先创建jason业务表的备份jason_old,再基于闪回数据创建新业务表jason_new,然后立即删除jason业务表误更新的数据,再将undo中前镜像数据插回至jason表,如下:

SQL> create table jason_old as select * from jason;
SQL> create table jason_new as select * from jason where 1=2;
SQL> insert into jason_new select * from sys.jason as of timestamp to_timestamp('2022-05-07 06:12:38','yyyy-mm-dd hh24:mi:ss') where object_id<=70000;
69346 rows created.
SQL> commit;
SQL> delete from jason where object_id<=70000;
SQL> commit;
SQL> insert into jason select * from jason_new;
69346 rows created.
SQL> commit;

如果数据无法通过undo闪回查询找到,则尝试1.2.3节方案进行数据挽救。

SQL> select count(*) from sys.jason as of timestamp to_timestamp('2022-05-07 06:12:38','yyyy-mm-dd hh24:mi:ss') where object_id<=70000;
ERROR at line 1:
ORA-01555: snapshot too old: rollback segment number 7 with name
"_SYSSMU7_2329891355$" too small

2.3归档日志挖掘恢复误删数据

检查数据库全局force_logging和supplemental_log_data_min特性是否开启,如下:

SQL> select name,open_mode,log_mode,force_logging,supplemental_log_data_min from v$database;
NAME      OPEN_MODE            LOG_MODE     FORCE_LOGGING   SUPPLEMENTAL_LOG_DATA_MIN
--------- -------------------- ------------ --------------- -------------------------
TESTDB19  READ WRITE           ARCHIVELOG   NO              NO

手动切换归档日志,并记录当前时间,如下:

SQL> alter system switch logfile;
SQL> select sysdate from dual;
SYSDATE
-------------------
2022-05-07 06:34:09

检查数据误删除期间产生的归档日志文件,如下:

select unique NAME, THREAD#, SEQUENCE#, COMPLETION_TIME
  from gv$archived_log
 where thread# = 1
   and COMPLETION_TIME >=
       to_date('2022-05-07 06:12:38', 'yyyy-mm-dd hh24:mi:ss')
   and COMPLETION_TIME <=
       to_date('2022-05-07 06:34:09', 'yyyy-mm-dd hh24:mi:ss')
 order by SEQUENCE#;

添加第一个要加载的归档日志文件,如下:

SQL> execute dbms_logmnr.add_logfile(logfilename=>'/oracle/app/fast_recovery_area/TESTDB19C/archivelog/2022_05_07/o1_mf_1_137_k7dlrmqx_.arc',options=>dbms_logmnr.new);

多次添加要加载的归档日志文件,如下:

SQL> execute dbms_logmnr.add_logfile(logfilename=>'/oracle/app/fast_recovery_area/TESTDB19C/archivelog/2022_05_07/o1_mf_1_138_k7dlrtnr_.arc',options=>dbms_logmnr.addfile);

执行日志挖掘分析,如下:

SQL> execute dbms_logmnr.start_logmnr(options=>dbms_logmnr.dict_from_online_catalog);

查询v$logmnr_contents动态性能视图,获取归档日志解析信息,如下:

SQL> select count(*) from v$logmnr_contents;
  COUNT(*)
----------
    345231
SQL> create table sys.hzmc_logmnr_contents as select * from v$logmnr_contents;

关闭日志挖掘分析,如下:

SQL> execute dbms_logmnr.end_logmnr;

将误删除操作的反向插入语句输出至jason_insert.sql,如下:

SQL> set lines 1000 pages 0
SQL> spool jason_update.sql
select sql_undo
  from sys.hzmc_logmnr_contents
 where OPERATION = 'UPDATE'
   and sql_redo like '%JASON%'
   and TIMESTAMP >= to_date('2022-05-07 06:12:38', 'yyyy-mm-dd hh24:mi:ss')
   and TIMESTAMP <= to_date('2022-05-07 06:34:09', 'yyyy-mm-dd hh24:mi:ss');
SQL> spool off

清理jason_update.sql文本中的首行和尾行,如下:

shell> vi jason_update.sql

将反向解析出来的SQL语句插回至jason业务表,如下:

SQL> @jason_update.sql


请使用浏览器的分享功能分享到微信等