代码改变世界

一看就会一做就废系列:说说 RECOVER UNTIL CANCEL

2019-06-13 11:50  askscuti  阅读(6957)  评论(0编辑  收藏  举报

这里是:一看就会,一做就废系列

数据库演示版本为 19.3 (12.2.0.3

该系列涉及恢复过程中使用的 个语句:

1. recover database

2. recover database until cancel

3. recover database using backup controlfile

4. recover database until cancel using backup controlfile

5. recover database using backup controlfile until cancel

继续之前,你得知道什么叫还原 ?什么叫恢复 ?以及备份与恢复的基础 点我查看己亥清爽系列

恢复级别一共三个:recover database > recover tablespace > recover datafile 本系列目的是为了演示上面 5 条命令的区别与联系,所以不探讨恢复级别以及数据库状态对应所使用的恢复级别问题。最高级别 database 已经包含了 tablespace 和 datafile 两个级别。

版权声明:博客园 AskScuti 版权所有,未经允许,禁止转载!

目录

1. 概念解释

  1.1 基于数据库时间点恢复(Database Point-in-Time Recovery)- RMAN

  1.2 基于取消的不完全恢复(Cancel-Based Incomplete Recovery)- SQL命令行

  1.3 基于时间 / SCN 的不完全恢复(Time-Based or Change-Based Incomplete Recovery)- SQL命令行

2. 情况说明

3. 实验过程

  3.1 备份 CDB

  3.2 创建测试数据

  3.3 删除所有数据文件

  3.4 破坏归档日志文件 

  3.5 重启数据库并进行还原操作

  3.6 恢复数据库

  3.7 打开数据库

  3.8 验证数据

 

1. 概念解释

先理解什么是 until :直到...时候,到...为止,只要见到 until 就知道是不完全恢复(注意:归档日志和在线日志都完整的情况下,如果你愿意,也可以使用 until 不完全恢复子句进行数据的完全恢复

until 子句的类型分为以下三大类:

1.1 基于数据库时间点恢复(Database Point-in-Time Recovery)- RMAN

  • until time '2019-01-01 12:00:00' 告诉数据库,给我(恢复)应用归档直到 12 点整为止
  • until scn 1234567 本条命令和上面命令一致,只不过 scn 是用在 RMAN 的,而 change 是用在 SQL 命令行的
  • until sequence 123 也可以在 RMAN 的 run 代码块里指定恢复到的日志序列号

1.2 基于取消的不完全恢复(Cancel-Based Incomplete Recovery)- SQL命令行

  • until cancel 仅在 SQL 命令行中有效

1.3 基于时间 / SCN 的不完全恢复(Time-Based or Change-Based Incomplete Recovery)- SQL命令行

  • until time '2019-01-01 12:00:00' 
  • until change 1234567 

其中 1.1 主要用于 RMAN 中的 run 代码块,在进行不完全恢复的时候,可以提前进行 set ,例如:

RUN
{
SET UNTIL SCN 1000;
RESTORE DATABASE;
RECOVER DATABASE;
}

你还可以将第一句替换为:

SET UNTIL TIME '2019-01-01 12:00:00';
SET UNTIL SEQUENCE 123;

1.2 和 1.3 小节指的是基于用户管理(手工)恢复,直接在 SQL 命令行中进行的恢复。这里分类,是为了单独讲解 1.2 小节。个人认为,1.1 小节中基于数据库时间点恢复其实包括了(Cancle-Based / Time-Based / Change-Based)这些,只不过是为了区分哪些是在 RMAN 里面做,哪些是在 SQL 命令行里面做。

recover database until cancel 这个命令只能在 SQL 命令行进行,它可以通过提示归档日志文件的建议名称进行主动恢复。也就是恢复应用到哪个归档,由你自己把控,如果在归档和联机日志都完整的情况下,你甚至可以通过不完全恢复的语句来实现数据的完全恢复

recover database until cancel 命令默认只会应用归档日志,而不会自动应用在线日志,这是和 recover database 的区别,后者自动应用所有归档和在线日志进行前滚操作

 

2. 情况说明

当前系统中,所有数据文件损坏、归档日志不连续、联机日志完好无损,删除 CDB 及 PDB 所有数据文件,并采用 RMAN 对所有数据文件进行还原,使用 recover database until cancel 进行不完全恢复。

通过 recover database until cancel 不完全恢复命令,进行完全恢复(条件是什么?如何操作?参考番外:recover database until cancel 的补充说明)

 

3. 实验过程

3.1 备份 CDB

RMAN> backup database format '/u02/backup/%d_%s_%U.full' tag='full';

3.2 创建测试数据

创建表,插入数据

SQL> create table henry(id number);

Table created.

SQL> insert into henry values(1);

1 row created.

SQL> insert into henry values(2);

1 row created.

SQL> insert into henry values(3);

1 row created.

SQL> commit;

Commit complete.

查看当前使用的日志组状态

SQL> select group#,sequence#,status from v$log;

    GROUP#  SEQUENCE# STATUS
---------- ---------- -------
     1        1     CURRENT
     2        0     UNUSED
     3        0     UNUSED

当前表数据 1,2,3 在 SEQUENCE 为 1 的日志组中

将表数据 1,2,3 进行归档操作

SQL> alter system switch logfile;

System altered.

SQL> alter system checkpoint;

System altered.

SQL> select group#,sequence#,status from v$log;

    GROUP#  SEQUENCE# STATUS
---------- ---------- --------
     1        1     INACTIVE
     2        2     CURRENT
     3        0     UNUSED

 

继续插入 4,5,6

SQL> insert into henry values(4);

1 row created.

SQL> insert into henry values(5);

1 row created.

SQL> insert into henry values(6);

1 row created.

SQL> commit;

Commit complete.

将表数据 4,5,6 切换日志进行归档操作

SQL> alter system switch logfile;

System altered.

SQL> alter system checkpoint;

System altered.

查看当前日志组状态

SQL> select group#,sequence#,status from v$log;

    GROUP#  SEQUENCE# STATUS
---------- ---------- --------
     1        1     INACTIVE
     2        2     INACTIVE
     3        3     CURRENT

表数据 1,2,3 在 1 号归档,4,5,6 在 2 号归档,现在数据库正在使用 sequence 为 3 的在线日志。

 

继续插入 7,8,9,不生成归档,数据 7,8,9 保留至 sequence 为 3 的在线日志里面

SQL> insert into henry values(7);

1 row created.

SQL> insert into henry values(8);

1 row created.

SQL> insert into henry values(9);

1 row created.

SQL> commit;

Commit complete.

SQL> select group#,sequence#,status from v$log;

    GROUP#  SEQUENCE# STATUS
---------- ---------- --------
     1        1     INACTIVE
     2        2     INACTIVE
     3        3     CURRENT

3.3 删除所有数据文件

SQL> select name from v$datafile;

NAME
-------------------------------------------------
/u01/app/oracle/oradata/CDB1/system01.dbf
/u01/app/oracle/oradata/CDB1/sysaux01.dbf
/u01/app/oracle/oradata/CDB1/undotbs01.dbf
/u01/app/oracle/oradata/CDB1/pdbseed/system01.dbf
/u01/app/oracle/oradata/CDB1/pdbseed/sysaux01.dbf
/u01/app/oracle/oradata/CDB1/users01.dbf
/u01/app/oracle/oradata/CDB1/pdbseed/undotbs01.dbf
/u01/app/oracle/oradata/CDB1/pdb1/system01.dbf
/u01/app/oracle/oradata/CDB1/pdb1/sysaux01.dbf
/u01/app/oracle/oradata/CDB1/pdb1/undotbs01.dbf
/u01/app/oracle/oradata/CDB1/pdb1/users01.dbf
/u01/app/oracle/oradata/CDB1/pdb1/henry01.dbf

删除

SQL> !rm -rf /u01/app/oracle/oradata/CDB1/pdb1/*

SQL> !rm -rf /u01/app/oracle/oradata/CDB1/pdbseed/*

SQL> !rm -rf /u01/app/oracle/oradata/CDB1/system01.dbf

SQL> !rm -rf /u01/app/oracle/oradata/CDB1/sysaux01.dbf

SQL> !rm -rf /u01/app/oracle/oradata/CDB1/undotbs01.dbf

SQL> !rm -rf /u01/app/oracle/oradata/CDB1/users01.dbf

3.4 破坏归档日志文件 

SQL> select name from v$archived_log;

NAME
----------------------------------------------------------------
/u02/oradata/CDB1/archivelog/2019_06_07/o1_mf_1_7_gho256t7_.arc
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_8_gj3c1t2j_.arc
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_9_gj3c1ttr_.arc
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_10_gj3c1z2n_.arc
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_11_gj3c4dvl_.arc
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_12_gj3crh2d_.arc
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_1_gj3go3on_.arc
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_2_gj3gpf1h_.arc

将 2 号归档进行重命名,使其不连续(该归档保存着 4,5,6)

SQL> !mv /u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_2_gj3gpf1h_.arc /u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_2_gj3gpf1h_.arc.bak

3.5 重启数据库并进行还原操作

SQL> startup force;
ORACLE instance started.

Total System Global Area 1241510120 bytes
Fixed Size                9134312 bytes
Variable Size            855638016 bytes
Database Buffers        369098752 bytes
Redo Buffers              7639040 bytes
Database mounted.
ORA-01157: cannot identify/lock data file 1 - see DBWR trace file
ORA-01110: data file 1: '/u01/app/oracle/oradata/CDB1/system01.dbf'

通过 RMAN 进行还原

[oracle@henry ~]$ rman target /

Recovery Manager: Release 19.0.0.0.0 - Production on Thu Jun 13 11:14:11 2019
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle and/or its affiliates.  All rights reserved.

connected to target database: CDB1 (DBID=983951798, not open)

RMAN> restore database from tag='full';

Starting restore at 13-JUN-19
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=11 device type=DISK

channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00001 to /u01/app/oracle/oradata/CDB1/system01.dbf
channel ORA_DISK_1: restoring datafile 00003 to /u01/app/oracle/oradata/CDB1/sysaux01.dbf
channel ORA_DISK_1: restoring datafile 00004 to /u01/app/oracle/oradata/CDB1/undotbs01.dbf
channel ORA_DISK_1: restoring datafile 00007 to /u01/app/oracle/oradata/CDB1/users01.dbf
channel ORA_DISK_1: reading from backup piece /u02/backup/CDB1_8_08u40523_1_1.full
channel ORA_DISK_1: piece handle=/u02/backup/CDB1_8_08u40523_1_1.full tag=FULL
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:01:05
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00009 to /u01/app/oracle/oradata/CDB1/pdb1/system01.dbf
channel ORA_DISK_1: restoring datafile 00010 to /u01/app/oracle/oradata/CDB1/pdb1/sysaux01.dbf
channel ORA_DISK_1: restoring datafile 00011 to /u01/app/oracle/oradata/CDB1/pdb1/undotbs01.dbf
channel ORA_DISK_1: restoring datafile 00012 to /u01/app/oracle/oradata/CDB1/pdb1/users01.dbf
channel ORA_DISK_1: restoring datafile 00013 to /u01/app/oracle/oradata/CDB1/pdb1/henry01.dbf
channel ORA_DISK_1: reading from backup piece /u02/backup/CDB1_9_09u4053r_1_1.full
channel ORA_DISK_1: piece handle=/u02/backup/CDB1_9_09u4053r_1_1.full tag=FULL
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:00:35
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00005 to /u01/app/oracle/oradata/CDB1/pdbseed/system01.dbf
channel ORA_DISK_1: restoring datafile 00006 to /u01/app/oracle/oradata/CDB1/pdbseed/sysaux01.dbf
channel ORA_DISK_1: restoring datafile 00008 to /u01/app/oracle/oradata/CDB1/pdbseed/undotbs01.dbf
channel ORA_DISK_1: reading from backup piece /u02/backup/CDB1_10_0au4054l_1_1.full
channel ORA_DISK_1: piece handle=/u02/backup/CDB1_10_0au4054l_1_1.full tag=FULL
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:00:36
Finished restore at 13-JUN-19
restore

3.6 恢复数据库

SQL> recover database until cancel;
ORA-00279: change 2255708 generated at 06/13/2019 10:47:31 needed for thread 1
ORA-00289: suggestion :
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_1_gj3go3on_.arc
ORA-00280: change 2255708 for thread 1 is in sequence #1


Specify log: {<RET>=suggested | filename | AUTO | CANCEL}

程序建议让我们应用 1 号归档  :/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_1_gj3go3on_.arc 

这里有三个选项:filename  AUTO  CANCEL

filename 可以进行手工指定归档日志文件名,主动进行,可以随时停止进行 CANCEL(如果最后指定的归档不存在,则报错,在线日志完整情况下,应该尝试手工输入在线日志名称,以达到完全恢复的效果)

AUTO 指定 AUTO 关键字后,会自动应用归档日志,直到最后一个可用归档(如果最后指定的归档不存在,则报错,在线日志完整情况下,应该尝试手工输入在线日志名称,以达到完全恢复的效果)

CANCEL 指定该关键字后,取消当前恢复(这个取消不是回滚所有操作的意思,而是当前取消,恢复到当前这个点)

注意:我们之前将归档 2 进行更名,故意让归档日志不连续。归档 2 里面保存着(4,5,6)

手工指定(filename)建议归档名称

SQL> recover database until cancel;
ORA-00279: change 2255708 generated at 06/13/2019 10:47:31 needed for thread 1
ORA-00289: suggestion :
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_1_gj3go3on_.arc
ORA-00280: change 2255708 for thread 1 is in sequence #1


Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_1_gj3go3on_.arc
ORA-00279: change 2255918 generated at 06/13/2019 10:53:23 needed for thread 1
ORA-00289: suggestion :
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_2_gj3gpf1h_.arc
ORA-00280: change 2255918 for thread 1 is in sequence #2
ORA-00278: log file
'/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_1_gj3go3on_.arc' no longer
needed for this recovery


Specify log: {<RET>=suggested | filename | AUTO | CANCEL}

这时,1 号归档恢复完毕,不再需要,建议给出继续应用 2 号归档:/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_2_gj3gpf1h_.arc

可是我们当前系统没有这个归档(被重命名),意味着归档无法继续前滚,因此数据将丢失,这时候输入 CANCEL 取消恢复即可。

SQL> recover database until cancel;
ORA-00279: change 2255708 generated at 06/13/2019 10:47:31 needed for thread 1
ORA-00289: suggestion :
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_1_gj3go3on_.arc
ORA-00280: change 2255708 for thread 1 is in sequence #1


Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_1_gj3go3on_.arc
ORA-00279: change 2255918 generated at 06/13/2019 10:53:23 needed for thread 1
ORA-00289: suggestion :
/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_2_gj3gpf1h_.arc
ORA-00280: change 2255918 for thread 1 is in sequence #2
ORA-00278: log file
'/u02/oradata/CDB1/archivelog/2019_06_13/o1_mf_1_1_gj3go3on_.arc' no longer
needed for this recovery


Specify log: {<RET>=suggested | filename | AUTO | CANCEL}
CANCEL
Media recovery cancelled.

完成恢复后,表中数据只有(1,2,3),(4,5,6)归档被重命名,因此无法应用,所以数据丢失,包括在线日志里面的(7,8,9)

3.7 打开数据库

因着执行了不完全恢复(即使某种情况下通过不完全恢复语句完成了数据的完全恢复),必须以 resetlogs 打开数据库。重置日志组 sequence 号,从 1 开始,新化身出现。

SQL> alter database open resetlogs;

Database altered.

3.8 验证数据

SQL> select * from henry;

    ID
----------
     1
     2
     3

因为只应用了 1 号归档(1,2,3),2 号归档被模拟损坏(4,5,6)无法应用,后面在线日志也无法应用(7,8,9),因为日志前滚必须连续,所以最终数据为 1,2,3