rman不完全恢复(时间点、SCN、CANCEL)、logmnr日志挖掘

1.不完全恢复(Point-In-Time Recovery)

​ 不完全恢复仅仅是将数据恢复到某一个特定的时间点或特定的SCN,而不是当前时间点。不完全恢复会整个CDB和非CDB会影响整个数据库,需要在MOUNT状态下进行。在不完全恢复成功之后,通常需要使用 resetlogs 选项来打开数据库。当使用resetlogs后,SCN 计数器不会被重置,原来的日志序号 log sequence 会结束,从新开始新的日志序列号。在Oracle里称之为产生一个新的incarnation。同时Oracle还会重置联机重做日志内容,因此resetlogs之后建议重新全备数据库。

1.1不完全恢复的情形:

  • 介质故障(media failure)导致部分或全部联机重做日志(online redo log)损坏。

  • 用户操作失误(user error)导致数据丢失,例如,用户由于疏忽而移除了表,提交了无效的数据到表。

  • 由于归档重做日志(archived redo log)丢失而无法进行完全恢复(complete recovery) 。

  • 当前控制文件(control file)丢失,必须使用备份的控制文件打开(open)数据库。

1.2不完全恢复的一些类型:

  • 基于时间点恢复,recover database until time "to_date('2020/04/10 13:00:00','YYYY/MM/DD HH24:MI:SS')";

  • 基于SCN恢复,recover database until scn 10000;

  • 基于CANCEL恢复,

  • 基于备份控制文件恢复

  • 基于重做日志序列号的恢复 (Log sequence recovery)将数据恢复到指定的重做日志序号(仅使用RMAN时有效)

    recover database until sequence 100 thread 1;

  • 基于还原点的恢复

    Create restore point rest_01;

    Recover database until restore point rest_01;

  • TSPITR

常用的有:

#基于TIME 参数不完全恢复
run { 
      shutdown immediate;
      startup mount;
      set until time "to_date('20201127 10:09:53','yyyymmdd hh24:mi:ss')";
      restore database;
      recover database;
      alter database open resetlogs;
}
 
#基于SCN 参数不完全恢复
run { 
      shutdown immediate;
      startup mount;
      set until scn 5436760; 
      restore database;
      recover database;
      alter database open resetlogs;
}
 
#基于SEQUENCE 参数不完全恢复:
run { 
      shutdown immediate;
      startup mount;
      set until sequence 1;
      restore database;
      recover database;
      alter database open resetlogs;
}

1.3pdb的不完全恢复

无论是CDB还是非CDB步骤大致一样:

  1. 关闭数据库并备份数据库(以防止恢复失败)

  2. 启动数据库到mount 状态

  3. 还原所有数据文件,同时可以选择还原控制文件(注意需要还原所有数据文件,而不仅仅是受损文件)

  4. 将数据库恢复至某个时间点、序列、或系统改变号

  5. 使用RESETLOGS关键字打开数据库

区别在于,PDB的恢复上,oracle可以使用辅助实例,就和RECOVER TABLE一样.

所需空间确保是源PDB一倍

1)	关闭PDB
	RMAN> alter pluggable database orclpdb close;

2)	还原PDB
	restore pluggable database orclpdb until time "to_date('2022/05/17 10:42:00','YYYY/MM/DD HH24:MI:SS')";
	recover pluggable database orclpdb until time "to_date('2022/05/17 10:42:00','YYYY/MM/DD HH24:MI:SS')";

3)	打开PDB
	alter pluggable database orclpdb open resetlogs;

2.logmnr日志挖掘

当前会话有效

2.1DML日志挖掘步骤

DML误操作优先级:

1. DML更优先使用闪回,`flashback query` `flashback table`使用undo,但时间长了可能undo被覆盖
2. 使用逻辑备份(expdp|impdp)
3. TSPITR基于表空间时间点
4. flashback database
5. rman不完全恢复

rman不完全恢复前,为了安全,一定要先全库备份。

rman不完全恢复最慢,要shutdown、restore and recover到一个时间点,消耗太大,所以尽量不选择使用

1)添加 database 补充日志
SQL>ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
注意:为了避免日志遗漏,这步要先执行。

2)确定要分析的日志范围,添加日志,分析
SQL>execute dbms_logmnr.add_logfile(logfilename=>'日志',options=>dbms_logmnr.new);
提供第一个要加载的日志文件
SQL>execute dbms_logmnr.add_logfile(logfilename=>'追加日志',options=>dbms_logmnr.addfile);
可以反复添加补充多个日志文件

3)执行 logmnr 分析
SQL>execute dbms_logmnr.start_logmnr(options=>dbms_logmnr.dict_from_online_catalog);
4)查询分析结果,
SQL>select username,scn,timestamp,sql_redo from v$logmnr_contents where seg_name='表名';
可以设置时间格式,也可以在显示方式里再确定格式.
#alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';设置日期格式



5)关闭日志分析
SQL>execute dbms_logmnr.end_logmnr;

2.1DDL日志挖掘步骤

11g之前到12c部分版本都能使用utl_file_dir

ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;

1)建立一个存放 dict.oral 的目录,设置参数 utl_file_dir 指定该目录,
$ mkdir /home/oracle/logmnr
SQL> alter system set utl_file_dir='/home/oracle/logmnr' scope=spfile;

2)建立数据字典文件 dict.ora
SQL> execute dbms_logmnr_d.build('dict.ora','/home/oracle/logmnr',dbms_logmnr_d.store_in_flat_file);

3)添加日志分析
SQL> execute dbms_logmnr.add_logfile(logfilename=>'日志文件',options=>dbms_logmnr.new);
SQL> execute dbms_logmnr.add_logfile(logfilename=>'追加日志',options=>dbms_logmnr.addfile);

4)执行分析
SQL> 
execute dbms_logmnr.start_logmnr(dictfilename=>
'/home/oracle/logmnr/dict.ora',options=>dbms_logmnr.ddl_dict_tracking);

5)查看分析结果
SQL> select username,scn,to_char(timestamp,'yyyy-mm-dd hh24:mi:ss'),sql_redo from v$logmnr_contents WHERE USERNAME 
='SCOTT' and lower(sql_redo) like '%table%';

6)关闭日志分析
SQL> execute dbms_logmnr.end_logmnr;

19c之后:

后utl_file_dir参数被抛弃,不再使用,当然也不用费事创建,使用更加简单

官方文档参考

ddl挖掘示例:

按照官方文档的使用方法:

步骤与之前相似,可以不用创建数据字典,直接在线即可
开启补充日志、添加文件、执行分析、查看结果
ddl区别在于参数:DBMS_LOGMNR.DDL_DICT_TRACKING

官方文档提供的一些选项:
EXECUTE DBMS_LOGMNR.START_LOGMNR(-
   OPTIONS => DBMS_LOGMNR.DICT_FROM_REDO_LOGS + -
              DBMS_LOGMNR.DDL_DICT_TRACKING + -
              DBMS_LOGMNR.COMMITTED_DATA_ONLY + -
              DBMS_LOGMNR.PRINT_PRETTY_SQL);
              
dbms_logmnr.start_logmnr(options=>DBMS_LOGMNR.DDL_DICT_TRACKING);


例子:------------------------------------------
SQL> truncate table t1;

Table truncated.

SQL> commit;

Commit complete.

测试环境没有数据变动,没有切换日志,这条ddl肯定在当前redo,通过sql找到当前日志为redo02.log

ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;

execute dbms_logmnr.add_logfile(logfilename=>'/u01/app/oracle/oradata/ORCL/redo02.log',options=>dbms_logmnr.new);
execute dbms_logmnr.add_logfile(logfilename=>'/u01/app/oracle/oradata/ORCL/redo01.log',options=>dbms_logmnr.addfile);

SQL> exec dbms_logmnr.start_logmnr(options=>DBMS_LOGMNR.DDL_DICT_TRACKING);

PL/SQL procedure successfully completed.


col sql_redo for a60
col username for a10
set linesize 200
set pagesize 100
#找到了这个时间点
SQL> select username,scn,timestamp,sql_redo from v$logmnr_contents where seg_name='T1';

USERNAME          SCN TIMESTAMP SQL_REDO
---------- ---------- --------- ------------------------------------------------------------
SYS           4093801 17-MAY-22 truncate table t1;

SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> select username,scn,timestamp,sql_redo from v$logmnr_contents where seg_name='T1';

USERNAME          SCN TIMESTAMP           SQL_REDO
---------- ---------- ------------------- ------------------------------------------------------------
SYS           4093801 2022-05-17 15:28:53 truncate table t1;

3.基于时间点的恢复示例(logmnr dml找到时间点)

3.1模拟dml操作

sqlplus abc/abc

#创建一张表
create table t1 as select * from all_objects;
SQL> select count(*) from tab1;

  COUNT(*)
----------
     67101

#插入数据
SQL> insert into tab1 select * from all_objects;

已创建 67102 行。

SQL> select count(*) from tab1;

  COUNT(*)
----------
    134203

#产生归档
alter system switch logfile;
insert into tab1 select * from all_objects;
alter system switch logfile;
SQL> select count(*) from tab1;

  COUNT(*)
----------
    201305


#delete操作
SQL> delete from tab1;
已删除 201305 行。

SQL> commit;
提交完成。

#delete后在进行insert、update
SQL> insert into tab1 select * from all_objects where OBJECT_ID=10;
已创建 1 行。
SQL> update tab1 set OBJECT_ID=333;
已更新 1 行。
SQL> commit;

3.2dml日志分析,找到准确时间点

#找到归档
SQL> select name from v$archived_log where name is not null;
NAME
--------------------------------------------------------------------------------
/u01/app/oracle/product/19.3/dbhome_1/dbs/arch1_19_1104360443.dbf
/u01/app/oracle/product/19.3/dbhome_1/dbs/arch1_20_1104360443.dbf
/u01/app/oracle/product/19.3/dbhome_1/dbs/arch1_21_1104360443.dbf

#找到在线日志
SQL> col member for a50
SQL> select group#,member from v$logfile;
    GROUP# MEMBER
---------- --------------------------------------------------
         3 /u01/app/oracle/oradata/ORCL/redo03.log
         2 /u01/app/oracle/oradata/ORCL/redo02.log
         1 /u01/app/oracle/oradata/ORCL/redo01.log

#查看当前日志组
SQL> select group#,sequence#,status from v$log;
    GROUP#  SEQUENCE# STATUS
---------- ---------- ----------------
         1         22 CURRENT
         2         20 INACTIVE
         3         21 INACTIVE
         
         
#添加database补充日志
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;

#添加第一个日志,分析。先添加一个归档日志分析(可以结合归档生成时间来判断)
execute dbms_logmnr.add_logfile(logfilename=>'/u01/app/oracle/product/19.3/dbhome_1/dbs/arch1_20_1104360443.dbf',options=>dbms_logmnr.new);

#添加后续的日志,ogmnr.new变为logmnr.addfile
execute dbms_logmnr.add_logfile(logfilename=>'/u01/app/oracle/product/19.3/dbhome_1/dbs/arch1_21_1104360443.dbf',options=>dbms_logmnr.addfile);

#添加在线日志
execute dbms_logmnr.add_logfile(logfilename=>'/u01/app/oracle/oradata/ORCL/redo01.log',options=>dbms_logmnr.addfile);

#执行 logmnr 分析
execute dbms_logmnr.start_logmnr(options=>dbms_logmnr.dict_from_online_catalog);

#查询结果,通过v$logmnr_contents视图查看,结果往往很多,根据适合条件限制
#alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';设置日期格式
select username,scn,timestamp,sql_redo from v$logmnr_contents where seg_name='TAB1' and rownum<=3;

col sql_redo for a60
col username for a10
set linesize 200
set pagesize 100

SQL> select username,scn,timestamp,sql_redo from v$logmnr_contents where seg_name='TAB1' and rownum<8;

USERNAME          SCN TIMESTAMP           SQL_REDO
---------- ---------- ------------------- ------------------------------------------------------------
UNKNOWN       5163131 2022-05-16 20:47:02 create table tab1 as select * from all_objects;
UNKNOWN       5164356 2022-05-16 20:48:45 insert into "ABC"."TAB1"("OWNER","OBJECT_NAME","SUBOBJECT_NA
                                          ME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LA
                                          ST_DDL_TIME","TIMESTAMP","STATUS","TEMPORARY","GENERATED","S
                                          ECONDARY","NAMESPACE","EDITION_NAME","SHARING","EDITIONABLE"
                                          ,"ORACLE_MAINTAINED","APPLICATION","DEFAULT_COLLATION","DUPL
                                          ICATED","SHARDED","CREATED_APPID","CREATED_VSNID","MODIFIED_
                                          APPID","MODIFIED_VSNID") values ('SYS','I_HH_OBJ#_INTCOL#',N
                                          ULL,'70','70','INDEX',TO_DATE('2019-04-17 00:56:15', 'yyyy-m
                                          m-dd hh24:mi:ss'),TO_DATE('2019-04-17 00:56:15', 'yyyy-mm-dd
                                           hh24:mi:ss'),'2019-04-17:00:56:15','VALID','N','N','N','4',
                                          NULL,'NONE',NULL,'Y','N',NULL,'N','N',NULL,NULL,NULL,NULL);

UNKNOWN       5164356 2022-05-16 20:48:45 insert into "ABC"."TAB1"("OWNER","OBJECT_NAME","SUBOBJECT_NA
                                          ME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LA
                                          ST_DDL_TIME","TIMESTAMP","STATUS","TEMPORARY","GENERATED","S
                                          ECONDARY","NAMESPACE","EDITION_NAME","SHARING","EDITIONABLE"
                                          ,"ORACLE_MAINTAINED","APPLICATION","DEFAULT_COLLATION","DUPL
                                          ICATED","SHARDED","CREATED_APPID","CREATED_VSNID","MODIFIED_
                                          APPID","MODIFIED_VSNID") values ('SYS','FIXED_OBJ$',NULL,'71
                                          ','71','TABLE',TO_DATE('2019-04-17 00:56:15', 'yyyy-mm-dd hh
                                          24:mi:ss'),TO_DATE('2019-04-17 00:56:15', 'yyyy-mm-dd hh24:m
                                          i:ss'),'2019-04-17:00:56:15','VALID','N','N','N','1',NULL,'M
                                          ETADATA LINK',NULL,'Y','N','USING_NLS_COMP','N','N',NULL,NUL
                                          L,NULL,NULL);

UNKNOWN       5164356 2022-05-16 20:48:45 insert into "ABC"."TAB1"("OWNER","OBJECT_NAME","SUBOBJECT_NA
                                          ME","OBJECT_ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LA
                                          ST_DDL_TIME","TIMESTAMP","STATUS","TEMPORARY","GENERATED","S
                                          ECONDARY","NAMESPACE","EDITION_NAME","SHARING","EDITIONABLE"
                                          ,"ORACLE_MAINTAINED","APPLICATION","DEFAULT_COLLATION","DUPL
                                          ICATED","SHARDED","CREATED_APPID","CREATED_VSNID","MODIFIED_
                                          APPID","MODIFIED_VSNID") values ('SYS','I_FIXED_OBJ$_OBJ#',N
                                          ULL,'72','72','INDEX',TO_DATE('2019-04-17 00:56:15', 'yyyy-m
                                          m-dd hh24:mi:ss'),TO_DATE('2019-04-17 00:56:15', 'yyyy-mm-dd
                                           hh24:mi:ss'),'2019-04-17:00:56:15','VALID','N','N','N','4',
                                          NULL,'NONE',NULL,'Y','N',NULL,'N','N',NULL,NULL,NULL,NULL);





#查看delete操作,加条件 lower(sql_redo) like 'delete%';

SQL> select username,scn,timestamp,sql_redo from v$logmnr_contents where seg_name='TAB1' and lower(sql_redo) like 'delete from%' and rownum<3;

USERNAME          SCN TIMESTAMP           SQL_REDO
---------- ---------- ------------------- ------------------------------------------------------------
UNKNOWN       5164635 2022-05-16 20:52:28 delete from "ABC"."TAB1" where "OWNER" = 'SYS' and "OBJECT_N
                                          AME" = 'I_FILE#_BLOCK#' and "SUBOBJECT_NAME" IS NULL and "OB
                                          JECT_ID" = '9' and "DATA_OBJECT_ID" = '9' and "OBJECT_TYPE"
                                          = 'INDEX' and "CREATED" = TO_DATE('2019-04-17 00:56:14', 'yy
                                          yy-mm-dd hh24:mi:ss') and "LAST_DDL_TIME" = TO_DATE('2019-04
                                          -17 00:56:14', 'yyyy-mm-dd hh24:mi:ss') and "TIMESTAMP" = '2
                                          019-04-17:00:56:14' and "STATUS" = 'VALID' and "TEMPORARY" =
                                           'N' and "GENERATED" = 'N' and "SECONDARY" = 'N' and "NAMESP
                                          ACE" = '4' and "EDITION_NAME" IS NULL and "SHARING" = 'NONE'
                                           and "EDITIONABLE" IS NULL and "ORACLE_MAINTAINED" = 'Y' and
                                           "APPLICATION" = 'N' and "DEFAULT_COLLATION" IS NULL and "DU
                                          PLICATED" = 'N' and "SHARDED" = 'N' and "CREATED_APPID" IS N
                                          ULL and "CREATED_VSNID" IS NULL and "MODIFIED_APPID" IS NULL
                                           and "MODIFIED_VSNID" IS NULL and ROWID = 'AAAR0xAAMAAAACDAA
                                          A';

UNKNOWN       5164635 2022-05-16 20:52:28 delete from "ABC"."TAB1" where "OWNER" = 'SYS' and "OBJECT_N
                                          AME" = 'I_OBJ3' and "SUBOBJECT_NAME" IS NULL and "OBJECT_ID"
                                           = '38' and "DATA_OBJECT_ID" = '38' and "OBJECT_TYPE" = 'IND
                                          EX' and "CREATED" = TO_DATE('2019-04-17 00:56:14', 'yyyy-mm-
                                          dd hh24:mi:ss') and "LAST_DDL_TIME" = TO_DATE('2019-04-17 00
                                          :56:14', 'yyyy-mm-dd hh24:mi:ss') and "TIMESTAMP" = '2019-04
                                          -17:00:56:14' and "STATUS" = 'VALID' and "TEMPORARY" = 'N' a
                                          nd "GENERATED" = 'N' and "SECONDARY" = 'N' and "NAMESPACE" =
                                           '4' and "EDITION_NAME" IS NULL and "SHARING" = 'NONE' and "
                                          EDITIONABLE" IS NULL and "ORACLE_MAINTAINED" = 'Y' and "APPL
                                          ICATION" = 'N' and "DEFAULT_COLLATION" IS NULL and "DUPLICAT
                                          ED" = 'N' and "SHARDED" = 'N' and "CREATED_APPID" IS NULL an
                                          d "CREATED_VSNID" IS NULL and "MODIFIED_APPID" IS NULL and "
                                          MODIFIED_VSNID" IS NULL and ROWID = 'AAAR0xAAMAAAACDAAB';

#找到delete时间点
    SCN         TIMESTAMP
5164635 2022-05-16 20:52:28



execute dbms_logmnr.end_logmnr;

3.3恢复

恢复之后控制文件新的,而日志文件时旧的,所以不完全恢复要resetlogs

shutdown immediate;
startup mount;

run {
allocate channel ch1 type disk ;        
allocate channel ch2 type disk;
sql'alter session set nls_date_format="yyyy-mm-dd hh24:mi:ss"';
set until time '2022-05-16 20:52:28';
restore database;
recover database;
alter database open resetlogs;
}

#restore database orclpdb until time "to_date('2022/05/17 10:42:00','YYYY/MM/DD HH24:MI:SS')";
#set until time "to_date('2022/05/17 10:42:00','YYYY/MM/DD HH24:MI:SS')";


#恢复到过去时间点,但是过去时间点到现在的数据没了


OBJECT_ID=333不存在

4.基于SCN的恢复

SCN转换成时间

select scn_to_timestamp(current_scn) from v$database;

时间转换成SCN

select timestamp_to_scn(sysdate) from v$database;

确定scn后,恢复

在ddl挖掘示例中得到scn
SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> select username,scn,timestamp,sql_redo from v$logmnr_contents where seg_name='T1';

USERNAME          SCN TIMESTAMP           SQL_REDO
---------- ---------- ------------------- ------------------------------------------------------------
SYS           4093801 2022-05-17 15:28:53 truncate table t1;



shutdown immediate;
startup mount;

run { 
      allocate channel ch1 type disk ;        
      allocate channel ch2 type disk;
      set until scn 4093801; 
      restore database;
      recover database;
      alter database open resetlogs;
}

5.基于CANCEL的恢复

基于终止的恢复

例如想要完全恢复时丢失了所需要的一些日志(可能是归档,也可能时redo)

最多只能恢复到丢失之前

run {
restore database;
recover database until cancel;
alter database open resetlogs;
}
posted @ 2022-05-17 21:26  EverEternity  阅读(777)  评论(0编辑  收藏  举报