己亥清爽系列说明:清爽系列是作为恢复系列的基础篇,基于FS(File System)文件系统的手工还原恢复,也叫基于用户管理的还原恢复,来自于博客园AskScuti。
实验说明:你不小心Drop掉了一张表数据,且没能及时反应过来,后面才恍然大悟,想利用闪回Drop技术进行闪回操作,可发现表空间被挤占,导致回收站里改表已被清空,又或者表是以Purge方式Drop掉的。如何进行手工不完全还原恢复操作。注:在数据文件、控制文件、在线日志和归档日志都完整的情况下。
基于版本:Oracle 11gR2 11.2.0.4 AskScuti
概念说明:请严格区分什么叫还原(Restore),什么叫恢复(Recover)。
还原(Restore):如果是基于用户管理(手工)的还原恢复,需要用户主动在系统层面进行拷贝粘贴,这个操作过程称之为还原;如果是基于恢复管理器(RMAN)的恢复,则通过Restore命令进行还原(自动进行),后者不在基础篇讨论。
恢复(Recover):在完成还原动作之后,数据回到了还原点,但从这个还原点到宕机时间点之间的数据,就要利用归档日志和在线日志进行前滚,直至应用到宕机前最后一次commit提交的状态(完全恢复),或应用到指定的某个时间点(不完全恢复)。
工作过程中,由于看错服务器连接,不小心 Drop 了一张表,之后某个时间点突然想到貌似 drop 错了,如何进行恢复。这个实验属于笨方法,但相对来说比较万能。
提示:这种情况,首选方法肯定是闪回技术中的闪回 Drop(闪回技术在11g里面一共有7种技术,其中5种基于UNDO,1种基于 Flashback logs 闪回日志,1种基于 Recycle bin 回收站,其中闪回 Drop 就是基于最后一种回收站技术),但如果 Drop 的这张表所对应的段空闲空间,在闪回之前被挤占(哪怕被挤占了一丢丢),那么回收站将会清空这张表,依然无法利用闪回 Drop。我们为了和基础恢复系列保持一致,本篇不采用闪回技术(闪回技术在以后其它博文单独列为一个专题,并在此处更新链接),而是选择一种比较笨但是有效的方法。
目录
1. 备份(手工冷备)
2. 实验
2.1 创建第一张表 henry_1
2.2 DROP第一张表 henry_1
2.3 创建第二张表 henry_2
2.4 全备当前数据库 (最新备份)
2.5 还原之前的备份 (之前备份)
2.6 恢复之前的数据文件(不完全恢复)
2.7 利用数据泵 expdp (传统导出 EXP )导出 henry_1
2.7.1 使用CTAS复制表 henry_1 到其它非受限模式下
2.7.2 使用传统EXP导出
2.8 还原刚才做的全备 (最新备份)
2.9 利用数据泵 impdp(传统导入 IMP )导入 henry_1
2.10 验证表数据
1. 备份
SQL> select name from v$datafile; SQL> select name from v$controlfile; SQL> select member from v$logfile; SQL> shutdown immediate; SQL> host cp /u01/app/oracle/oradata/PROD1/*.dbf /u01/app/oracle/backup/ SQL> host cp /u01/app/oracle/oradata/PROD1/*.ctl /u01/app/oracle/backup/ SQL> host cp /u01/app/oracle/fast_recovery_area/PROD1/control02.ctl /u01/app/oracle/backup/ SQL> host cp /u01/app/oracle/oradata/PROD1/*.log /u01/app/oracle/backup/ SQL> startup
2. 实验
2.1 创建第一张表 henry_1
创建 henry_1 表并插入数据
SQL> create table henry_1(id number) tablespace users; Table created. SQL> insert into henry_1 values(1); 1 row created. SQL> insert into henry_1 values(2); 1 row created. SQL> insert into henry_1 values(3); 1 row created. SQL> commit; Commit complete.
2.2 DROP第一张表 henry_1
因为是实验,你在删除前,可以先记录下当前的系统时间或SCN号,便于后面做不完全恢复(select sysdate/current_scn from dual;)。
SQL> drop table henry_1 purge; Table dropped.
2.3 创建第二张表 henry_2
SQL> create table henry_2(id number) tablespace users; Table created. SQL> insert into henry_2 values(1); 1 row created. SQL> insert into henry_2 values(2); 1 row created. SQL> insert into henry_2 values(3); 1 row created. SQL> insert into henry_2 values(4); 1 row created. SQL> insert into henry_2 values(5); 1 row created. SQL> commit; Commit complete.
2.4 全备当前数据库 (最新备份)
当 henry_2 表创建插入了5行数据并提交后,突然想起,henry_1表drop错了。干净一致的关闭数据库,做全备。
SQL> shutdown immediate; Database closed. Database dismounted. ORACLE instance shut down. SQL> host mkdir /u01/app/oracle/backup/new SQL> host cp /u01/app/oracle/oradata/PROD1/*.dbf /u01/app/oracle/backup/new/ SQL> host cp /u01/app/oracle/oradata/PROD1/*.ctl /u01/app/oracle/backup/new/ SQL> host cp /u01/app/oracle/fast_recovery_area/PROD1/control02.ctl /u01/app/oracle/backup/new/ SQL> host cp /u01/app/oracle/oradata/PROD1/*.log /u01/app/oracle/backup/new/
2.5 还原之前的备份 (之前备份)
注意:还原之前最近的一次的所有数据文件备份(不是2.4最新的备份)。例如:你们公司数据量不大,一天一次基于用户管理的全库冷备,那么今天不小心 Drop 了表,关闭当前数据库,做最新全备,然后还原昨天的数据文件全备。
SQL> host cp /u01/app/oracle/backup/*.dbf /u01/app/oracle/oradata/PROD1/
2.6 恢复之前的数据文件(不完全恢复)
还原所有数据文件,之后利用日志一起前滚,做不完全恢复,直至恢复到 henry_1 被删除的那一点之前(具体这个时间点如何找,如果你开了审计,通过审计找,绝大部分公司都不会开Oracle审计(耗费资源),有些公司使用第三方审计。你也可以通过LogMiner日志挖掘去找,尤其是业务库,在无法使用闪回 Drop 的时候,这种方式是很有必要的)。
恢复的语句注意下:在基于用户管理的不完全恢复中,可以使用 until time (也可以使用 until change xxxxx),你是不是想说还有 until scn xxxxx?,一定注意until后面的关键字,使用手工基于SCN的恢复要使用 until change xxxxx,使用RMAN基于SCN的恢复要使用 until scn xxxxx 。(xxxxx 是 SCN 号)
SQL> startup mount ORACLE instance started. Total System Global Area 417546240 bytes Fixed Size 2228944 bytes Variable Size 293604656 bytes Database Buffers 117440512 bytes Redo Buffers 4272128 bytes Database mounted. SQL> select * from v$recover_file; SQL> recover database until time '2019-05-20 18:30:00'; Media recovery complete. SQL> alter database open resetlogs; Database altered.
2.7 利用数据泵 expdp (传统导出 EXP )导出 henry_1
数据库打开之后,查询 henry_1 数据是否完整,再利用 expdp 逻辑导出。
SQL> select * from henry_1; ID ---------- 1 2 3
注意:由于我们实验环境直接在 SYS 用户下面创建的表,而11g里面是无法通过数据泵来导出 SYS 模式下的对象的(不仅仅是SYS),如果直接expdp则报错(ORA-39166/ORA-31655)。
ORA-39166: Object SYS.HENRY_1 was not found. ORA-31655: no data or metadata objects selected for job Job "SYS"."SYS_EXPORT_TABLE_01" completed with 2 error(s) at 19:19:16
在线官方文档对此问题的描述
MOS文档对此问题描述
DataPump Export (EXPDP) Fails With Error ORA-39165: Schema SYS Was Not Found (文档 ID 553402.1) There is a restriction on DataPump export. It cannot export schemas like SYS, ORDSYS, EXFSYS, MDSYS, DMSYS, CTXSYS, ORDPLUGINS, LBACSYS, XDB, SI_INFORMTN_SCHEMA, DIP, DBSNMP and WMSYS in any mode. The Utilities Guide indicates the restriction only on full export mode, but the restriction actually applies to all modes.
总之一句话:就是标红的这些用户(模式)下面的对象不能通过数据泵导出。(需要说明的是:如果当初你是在其它普通模式下创建的表,比如SCOTT普通用户下,就不会存在expdp报错这个问题)
解决方案(两种)
2.7.1 使用CTAS复制表 henry_1 到其它非受限模式下
比如,将SYS用户下的 henry_1 表复制到 SCOTT用户下。
SQL> create table scott.henry_1 as select * from henry_1; Table created.
然后再进行表的导出
SQL> host mkdir /u01/app/oracle/backup/dump SQL> create directory backup_dir as '/u01/app/oracle/backup/dump'; Directory created. SQL> select * from dba_directories where directory_name='BACKUP_DIR'; OWNER DIRECTORY_ DIRECTORY_PATH ----- ---------- --------------------------- SYS BACKUP_DIR /u01/app/oracle/backup/dump SQL> grant read,write on directory backup_dir to system; Grant succeeded. [oracle@henry dump]$ expdp 'sys/oracle as sysdba' directory=backup_dir dumpfile=expdp_henry_1.dmp logfile=expdp_henry_1.log tables=scott.henry_1 Export: Release 11.2.0.4.0 - Production on Mon May 20 19:58:30 2019 Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options Starting "SYS"."SYS_EXPORT_TABLE_01": "sys/******** AS SYSDBA" directory=backup_dir dumpfile=expdp_henry_1.dmp logfile=expdp_henry_1.log tables=scott.henry_1 Estimate in progress using BLOCKS method... Processing object type TABLE_EXPORT/TABLE/TABLE_DATA Total estimation using BLOCKS method: 64 KB Processing object type TABLE_EXPORT/TABLE/TABLE . . exported "SCOTT"."HENRY_1" 5.023 KB 3 rows Master table "SYS"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded ****************************************************************************** Dump file set for SYS.SYS_EXPORT_TABLE_01 is: /u01/app/oracle/backup/dump/expdp_henry_1.dmp Job "SYS"."SYS_EXPORT_TABLE_01" successfully completed at 19:58:40
2.7.2 使用传统EXP导出
或者使用传统导出EXP(注意:传统导入导出,与数据泵导入导出是两个东西,EXP 导出的东西,不能用数据泵 IMPDP 导入,反之也一样)
[oracle@henry dump]$ exp 'sys/oracle as sysdba' file=expdp_henry_1.dmp log=expdp_henry_1.log tables=sys.henry_1 Export: Release 11.2.0.4.0 - Production on Mon May 20 19:56:26 2019 Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set server uses AL32UTF8 character set (possible charset conversion) About to export specified tables via Conventional Path ... . . exporting table HENRY_1 3 rows exported Export terminated successfully without warnings.
2.8 还原刚才做的全备 (最新备份)
还原2.4做的全备(注意:还原所有数据文件、控制文件和在线日志文件),并打开数据库。
[oracle@henry dump]$ sqlplus / as sysdba SQL> shutdown abort; ORACLE instance shut down. SQL> host cp /u01/app/oracle/backup/new/*.dbf /u01/app/oracle/oradata/PROD1/ SQL> host cp /u01/app/oracle/backup/new/*.log /u01/app/oracle/oradata/PROD1/ SQL> host cp /u01/app/oracle/backup/new/control01.ctl /u01/app/oracle/oradata/PROD1/ SQL> host cp /u01/app/oracle/backup/new/control02.ctl /u01/app/oracle/fast_recovery_area/PROD1/ SQL> startup ORACLE instance started. Total System Global Area 417546240 bytes Fixed Size 2228944 bytes Variable Size 301993264 bytes Database Buffers 109051904 bytes Redo Buffers 4272128 bytes Database mounted. Database opened.
因为数据文件、控制文件和日志文件全部还原,三者SCN号一致,所以直接打开数据库,最后,通过传统导入 IMP 命令将 henry_1 表导入数据库(之所用 IMP 是为了对应 2.7.2 的传统导出)。
2.9 利用数据泵 impdp(传统导入 IMP )导入 henry_1
查询当前数据库,表被 Drop 掉:
SQL> select * from henry_1; select * from henry_1 * ERROR at line 1: ORA-00942: table or view does not exist
传统导入 IMP 命令进行导入(注意传统导入语法):
[oracle@henry dump]$ imp 'sys/oracle as sysdba' file=expdp_henry_1.dmp log=impdp_henry_1.log full=y Import: Release 11.2.0.4.0 - Production on Mon May 20 20:33:33 2019 Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options Export file created by EXPORT:V11.02.00 via conventional path import done in ZHS16GBK character set and AL16UTF16 NCHAR character set import server uses AL32UTF8 character set (possible charset conversion) . importing SYS's objects into SYS . importing SYS's objects into SYS . . importing table "HENRY_1" 3 rows imported Import terminated successfully without warnings.
2.10 验证表数据
再次查询 henry_1 表:
[oracle@henry dump]$ sqlplus / as sysdba SQL> select * from henry_1; ID ---------- 1 2 3 SQL> select * from henry_2; ID ---------- 1 2 3 4 5