大家好,这里是公众号 DBA学习之路,分享一些学习数据库路上的知识和经验。

前言
本章目标:掌握本章核心知识点
前置要求:完成前序章节学习
预计时长:60 分钟
常在河边走,哪能不湿鞋?
今天有客户联系说误更新数据表,导致数据错乱了,希望将这张表恢复到 一周前 的指定时间点。
- 数据库版本为
11.2.0.1
- 操作系统是
Windows64
- 数据已经被更改超过1周时间
- 数据库已开启归档模式
- 没有DG容灾
- 有RMAN备份
下面模拟一下问题的详细解决过程!
一、分析
以下只列出常规恢复手段:
- 数据已经误操作超过一周,所以排除使用UNDO快照来找回;
- 没有DG容灾环境,排除使用DG闪回;
- 主库已开启归档模式,并且存在RMAN备份,可使用RMAN异机恢复表对应表空间,使用DBLINK捞回数据表;
- Oracle 12C后支持单张表恢复;
结论:安全起见,使用RMAN异机恢复表空间来捞回数据表。
二、思路
客户希望将表数据恢复到 <2021/06/08 17:00:00> 之前某个时间点。
大致操作步骤如下:
- 主库查询误更新数据表对应的表空间和无需恢复的表空间。
- 新主机安装Oracle 11.2.0.1数据库软件,无需建库,目录结构最好保持一致。
- 主库拷贝参数文件,密码文件至新主机,根据新主机修改参数文件和创建新实例所需目录。
- 新主机使用修改后的参数文件打开数据库实例到nomount状态。
- 主库拷贝备份的控制文件至新主机,新主机使用RMAN恢复控制文件,并且MOUNT新实例。
- 新主机RESTORE TABLESPACE恢复至时间点 <2021/06/08 16:00:00>。
- 新主机RECOVER DATABASE SKIP TABLESPACE恢复至时间点 <2021/06/08 16:00:00>。
- 新主机实例开启到只读模式。
- 确认新主机实例的表数据是否正确,若不正确则重复 第7步 调整时间点慢慢往 <2021/06/08 17:00:00> 推进恢复。
- 主库创建连通新主机实例的DBLINK,通过DBLINK从新主机实例捞取表数据。
📢 注意: 选择表空间恢复是因为主库数据量比较大,如果全库恢复需要大量时间。
三、测试环境模拟
为了数据脱敏,因此以测试环境模拟场景进行演示!
⭐️ 测试环境可以使用脚本安装,可以使用博主编写的 Oracle 一键安装脚本,同时支持单机和 RAC 集群模式!
更多更详细的脚本使用方式可以订阅专栏:Oracle 一键安装脚本实操合集,持续更新中!!!。
1、环境准备
测试环境信息如下:
| 节点 | 主机版本 | 主机名 | 实例名 | Oracle版本 | IP地址 |
|---|
| 主库 | rhel6.9 | orcl | orcl | 11.2.0.1 | 10.211.55.111 |
| 新主机 | rhel6.9 | orcl | 不创建实例 | 11.2.0.1 | 10.211.55.112 |
2、模拟测试场景
主库开启归档模式:
1sqlplus / as sysdba
2## 设置归档路径
3alter system set log_archive_dest_1='LOCATION=/archivelog';
4## 重启开启归档模式
5shutdown immediate
6startup mount
7alter database archivelog;
8## 打开数据库
9alter database open;
创建测试数据:
1sqlplus / as sysdba
2## 创建表空间
3create tablespace lucifer datafile '/oradata/orcl/lucifer01.dbf' size 10M autoextend off;
4create tablespace ltest datafile '/oradata/orcl/ltest01.dbf' size 10M autoextend off;
5## 创建用户
6create user lucifer identified by lucifer;
7grant dba to lucifer;
8## 创建表
9conn lucifer/lucifer
10create table lucifer(id number not null,name varchar2(20)) tablespace lucifer;
11## 插入数据
12insert into lucifer values(1,'lucifer');
13insert into lucifer values(2,'test1');
14insert into lucifer values(3,'test2');
15commit;

进行数据库全备:
1rman target /
2## 进入 rman 后执行以下命令
3run {
4allocate channel c1 device type disk;
5allocate channel c2 device type disk;
6crosscheck backup;
7crosscheck archivelog all;
8sql"alter system switch logfile";
9delete noprompt expired backup;
10delete noprompt obsolete device type disk;
11backup database include current controlfile format '/backup/backlv0_%d_%T_%t_%s_%p';
12backup archivelog all DELETE INPUT;
13release channel c1;
14release channel c2;
15}

模拟数据修改:
1sqlplus / as sysdba
2conn lucifer/lucifer
3delete from lucifer where id=1;
4update lucifer set name='lucifer' where id=2;
5commit;

📢 注意: 为了模拟客户环境,假设无法通过UNDO快照找回,当前删除时间点为:<2021/06/17 18:10:00>。
如果使用UNDO快照,比较方便:
1sqlplus / as sysdba
2## 查找UNDO快照数据是否正确
3select * from lucifer.lucifer as of timestamp to_timestamp('2021-06-17 18:05:00','YYYY-MM-DD HH24:MI:SS');
4## 将UNDO快照数据捞至新建表中
5create table lucifer.lucifer_0617 as select * from lucifer.lucifer as of timestamp to_timestamp('2021-06-17 18:05:00','YYYY-MM-DD HH24:MI:SS');

四、RMAN完整恢复过程
主库查询误更新数据表对应的表空间和无需恢复的表空间:
1sqlplus / as sysdba
2## 查询误更新数据表对应表空间
3select owner,tablespace_name from dba_segments where segment_name='LUCIFER';
4## 查询所有表空间
5select tablespace_name from dba_tablespaces;


主库拷贝参数文件,密码文件至新主机,根据新主机修改参数文件和创建新实例所需目录:
1## 生成pfile参数文件
2sqlplus / as sysdba
3create pfile='/home/oracle/pfile.ora' from spfile;
4exit;
5## 拷贝至新主机
6su - oracle
7scp /home/oracle/pfile.ora 10.211.55.112:/tmp
8scp $ORACLE_HOME/dbs/orapworcl 10.211.55.112:$ORACLE_HOME/dbs
9## 新主机根据实际情况修改参数文件并且创建目录
10mkdir -p /u01/app/oracle/admin/orcl/adump
11mkdir -p /oradata/orcl/
12mkdir -p /archivelog
13chown -R oracle:oinstall /archivelog
14chown -R oracle:oinstall /oradata

新主机使用修改后的参数文件打开数据库实例到nomount状态:
1sqlplus / as sysdba
2startup nomount pfile='/tmp/pfile.ora';

主库拷贝备份的控制文件至新主机,新主机使用RMAN恢复控制文件,并且MOUNT新实例:
1rman target /
2list backup of controlfile;
3exit;
4## 拷贝备份文件至新主机
5scp /backup/backlv0_ORCL_20210617_107548592* 10.211.55.112:/tmp
6scp /u01/app/oracle/product/11.2.0/db/dbs/0c01l775_1_1 10.211.55.112:/tmp
7## 新主机恢复控制文件并开启到mount状态
8rman target /
9restore controlfile from '/tmp/backlv0_ORCL_20210617_1075485924_9_1';
10alter database mount;
通过 list backup of controlfile; 可以看到控制文件位置:



新主机RESTORE TABLESPACE恢复至时间点 <2021/06/17 18:06:00> :
1## 新主机注册备份集
2rman target /
3catalog start with '/tmp/backlv0_ORCL_20210617_107548592';
4crosscheck backup;
5delete noprompt expired backup;
6delete noprompt obsolete device type disk;
7## 恢复表空间LUCIFER和系统表空间,指定时间点 `2021/06/17 18:06:00`
8run {
9sql 'alter session set nls_date_format="yyyy-mm-dd hh24:mi:ss"';
10set until time '2021-06-17 18:06:00';
11allocate channel ch01 device type disk;
12allocate channel ch02 device type disk;
13restore tablespace SYSTEM,SYSAUX,UNDOTBS1,USERS,LUCIFER;
14release channel ch01;
15release channel ch02;
16}

新主机RECOVER DATABASE SKIP TABLESPACE恢复至时间点 <2021/06/17 18:06:00> :
1rman target /
2run {
3sql 'alter session set nls_date_format="yyyy-mm-dd hh24:mi:ss"';
4set until time '2021-06-17 18:06:00';
5allocate channel ch01 device type disk;
6recover database skip tablespace LTEST,EXAMPLE;
7release channel ch01;
8}

这里有一个小BUG: 客户环境是Windows,执行这一步最后报错,手动offline数据文件依然无法开启数据库。

解决方案:
1sqlplus / as sysdba
2## 将恢复跳过的表空间都offline drop掉,执行以下查询结果
3select 'alter database datafile '|| file_id ||' offline drop;' from dba_data_files where tablespace_name in ('LTEST','EXAMPLE');
4## 再次开启数据库
5alter database open read only;
📢 注意: 如果显示缺归档日志,可以参考如下步骤:
1sqlplus / as sysdba
2## 查询恢复需要的归档日志号时间
3alter session set nls_date_format="yyyy-mm-dd hh24:mi:ss";
4select first_time,sequence# from v$archived_log where sequence#='7';
5exit;
6## 通过备份RESTORE吐出所需的归档日志
7rman target /
8catalog start with '/tmp/0c01l775_1_1';
9crosscheck archivelog all;
10run {
11allocate channel ch01 device type disk;
12SET ARCHIVELOG DESTINATION TO '/archivelog';
13restore ARCHIVELOG SEQUENCE 7;
14release channel ch01;
15}
16## 再次recover进行恢复至指定时间点 2021-06-17 18:06:00
17run {
18sql 'alter session set nls_date_format="yyyy-mm-dd hh24:mi:ss"';
19set until time '2021-06-17 18:06:00';
20allocate channel ch01 device type disk;
21recover database skip tablespace LTEST,EXAMPLE;
22release channel ch01;
23}
新主机实例开启到只读模式:
1sqlplus / as sysdba
2alter database open read only;
确认新主机实例的表数据是否正确:
1sqlplus / as sysdba
2select * from lucifer.lucifer;

📢 注意: 若不正确则重复 第7步 调整时间点慢慢往 2021/06/17 18:10:00 推进恢复:
1## 关闭数据库
2sqlplus / as sysdba
3shutdown immediate;
4## 开启数据库到mount状态
5startup mount pfile='/tmp/pfile.ora';
6## 重复 第7步,往前推进1分钟,调整时间点为 `2021/06/08 18:07:00`
7rman target /
8run {
9sql 'alter session set nls_date_format="yyyy-mm-dd hh24:mi:ss"';
10set until time '2021-06-17 18:07:00';
11allocate channel ch01 device type disk;
12recover database skip tablespace LTEST,EXAMPLE;
13release channel ch01;
14}
主库创建连通新主机实例的DBLINK,通过DBLINK从新主机实例捞取表数据:
1sqlplus / as sysdba
2## 创建dblinnk
3CREATE PUBLIC DATABASE LINK ORCL112
4CONNECT TO lucifer
5IDENTIFIED BY lucifer
6USING '(DESCRIPTION_LIST=
7(DESCRIPTION=
8(ADDRESS=(PROTOCOL=tcp)(HOST=10.211.55.112)(PORT=1521))
9(CONNECT_DATA=
10(SERVICE_NAME=orcl)
11)
12)
13)';
14## 通过dblink捞取数据
15create table lucifer.lucifer_0618 as select /*+full(lucifer)*/ * from lucifer.lucifer@ORCL112;
16select * from lucifer.lucifer_0618;

至此,整个RMAN恢复过程就结束了!
写在最后
备份永远是最后一道防线,所以备份一定要做好!!!
往期精彩文章
