使用闪回查询恢复误删除的数据

某日,一个朋友的数据库数据被误操作删除(delete)掉了,并且已经提交请求请我帮忙进行恢复。数据库版本是Oracle 10g Release 2的,我首先想到的是使用Flashback Query进行闪回恢复,不幸的是出现了ORA- 01555,数据已经不能被闪回了。

Oracle从9i开始推出的闪回查询特性被一直不断增强着,闪回查询通过对回滚段中存储的前镜像数据进行追溯,可以获得变更之前的数据,从而在前镜像被覆盖之前,提供一种快捷的恢复和回退方式,在Oracle Database 11g中,Oracle更加引入了闪回数据归档的新特性,允许将前镜像数据通过独立的表空间进行归档,从而提供长达数年的历史追溯。

闪回特性受到初始化参数UNDO_RETENTION的影响,这个参数在10g中默认地设置为900秒,这个时间长度一般是不够的,我们可以根据数据库的具体情况,酌情调高这个参数,将前镜像的期望保留时间延长,一般习惯将这个参数修改为10 800秒,即3个小时(代码如下):ALTERSYSTEMSETundo_retention=10800 SCOPE=BOTH;

但请注意,增大这个参数可能会导致更多的UNDO表空间使用,以前在Oracle 9iR2中,这个参数的默认值一度被设为10 800秒,可是随之而来的问题可能是UNDO表空间的过分扩展,不易回收,所以Oracle在不同版本中,也在进行不停地折中,不断尝试不同的初始化参数设置。Oracle也许会这样想:如果很少有人使用Flashback Query,而过大的UNDO_RETENTION又会带来麻烦,那么干脆,设小点。

而根据我们的经验,在初始化创建数据库之后,UNDO_RETENTION的设置应该被修改,这一经验性调整应该被更新入安装手册,在数据库创建之后即刻进行。

然而在生产环境中修改这样一个参数需要谨慎,事实上,我们提醒DBA们要养成一些良好的习惯,如:

1. 尽量在测试后才在生产环境中执行某些维护操作。

2. 在生产环境空闲时才执行某些特定的维护操作。

在RAC环境中,修改某些数据库参数更须谨慎,有客户遇到了这样的问题,在Oracle 10gR1 RAC环境下修改UNDO_RETENTION参数,使用如下命令:altersystemsetundo_retention=18000 sid='*';

这条命令直接导致了RAC的其他节点挂起,Oracle记录了一个相关Bug,Bug号为4220405,Oracle提示不指定具体SID的UNDO_RETENTION修改在该版本中不被支持,其Workaround就是,分别修改不同实例:

altersystemsetundo_retention=18000 sid='RAC1';
altersystemsetundo_retention=18000 sid='RAC2';
altersystemsetundo_retention=18000 sid='RAC3';
......

Oracle声明在Oracle Database 11g中改正了以上这一问题,笔者曾经在10.2.0.4版本中测试过,证实已经不存在这个问题了。

这样一个简单的案例告诉我们,数据库的Bug可能无处不在,生产数据库调整应当极其谨慎,对于DBA来说,养成一些良好的工作习惯对于减少故障非常重要。

以下是一个简单的通过闪回查询恢复误删除数据的案例,这一特性应当为DBA所熟知。

某日下午接到研发工程师的电话,说误删除了部分重要数据,并且已经提交,需要恢复。登录到数据库上查看,由于是Oracle9iR2,首先尝试使用flashback query闪回数据。

数据库运行在归档模式,可以首先通过V$ARCHIVED_LOG视图来确认数据库的SCN变化,如下所示:SQL> col fscnfor9999999999999999999

SQL> col nscnfor9999999999999999999
SQL>selectname,FIRST_CHANGE# fscn,NEXT_CHANGE#
nscn,FIRST_TIMEfromv$archived_log;
NAMEFSCN
NSCN    FIRST_TIME
------------------------------  ------------
--------------------    -------------------
/mwarch/oracle/1_52413.dbf      12929941968
12929942881 2005-06-22 14:38:28
/mwarch/oracle/1_52414.dbf      12929942881
12929943706 2005-06-22 14:38:32
/mwarch/oracle/1_52415.dbf      12929943706
12929944623 2005-06-22 14:38:35
/mwarch/oracle/1_52416.dbf      12929944623
12929945392 2005-06-22 14:38:38
/mwarch/oracle/1_52417.dbf      12929945392
12929945888 2005-06-22 14:38:41
/mwarch/oracle/1_52418.dbf      12929945888
12929945965 2005-06-22 14:38:44
/mwarch/oracle/1_52419.dbf      12929945965
12929948945 2005-06-22 14:38:45
/mwarch/oracle/1_52420.dbf      12929948945
12929949904     2005-06-22 14:46:05
/mwarch/oracle/1_52421.dbf      12929949904
12929950854     2005-06-22 14:46:08
/mwarch/oracle/1_52422.dbf      12929950854
12929951751     2005-06-22 14:46:11
/mwarch/oracle/1_52423.dbf      12929951751
12929952587     2005-06-22 14:46:14
...................
/mwarch/oracle/1_52498.dbf      12930138975
12930139212     2005-06-22 15:55:57
/mwarch/oracle/1_52499.dbf      12930139212
12930139446     2005-06-22 15:55:59
/mwarch/oracle/1_52500.dbf      12930139446
12930139682     2005-06-22 15:56:00
/mwarch/oracle/1_52501.dbf      12930139682
12930139915     2005-06-22 15:56:02
/mwarch/oracle/1_52502.dbf      12930139915
12930140149     2005-06-22 15:56:03
/mwarch/oracle/1_52503.dbf      12930140149
12930140379     2005-06-22 15:56:05
/mwarch/oracle/1_52504.dbf      12930140379
12930140610     2005-06-22 15:56:05
/mwarch/oracle/1_52505.dbf      12930140610
12930140845     2005-06-22 15:56:07

获得当前的SCN为:SQL>selectdbms_flashback.get_system_change_number fscnfromdual;

FSCN

--------------------

12930142214

使用应用用户尝试闪回:SQL>connectusername/password

Connected.

现有数据:SQL>selectcount(*)fromhs_passport;

COUNT(*)

----------

851998

创建恢复表如下:SQL>createtablehs_passport_recovasselect*

fromhs_passportwhere1=0;

Tablecreated.

根据开发人员提供的大致误操作时间,结合V$ARCHIVED_LOG视图,选择适当SCN向前执行闪回查询:SQL>selectcount(*)fromhs_passportasofscn 12929970422;

COUNT(*)

----------

861686

尝试多个SCN,获取***值(如果能得知具体时间,那么可以获得准确的数据闪回):SQL>selectcount(*)fromhs_passportasofscn &scn;

Enter valueforscn: 12929941968
COUNT(*)
----------
861684
SQL> /
Enter valueforscn:    12927633776
selectcount(*)fromhs_passportasofscn 12927633776
*
ERRORatline 1:
ORA-01466: unabletoreaddata -tabledefinition has changed
SQL> /
Enter valueforscn: 12929928784
COUNT(*)
----------
825110
SQL> /
Enter valueforscn: 12928000000
selectcount(*)fromhs_passportasofscn 12928000000
*
ERRORatline 1:
ORA-01466: unabletoreaddata -tabledefinition has changed

***选择恢复到SCN为12929941968的时间点,代码如下:

SQL>insertintohs_passport_recovselect*
fromhs_passportasofscn 12929941968;
861684rowscreated.
SQL>commit;
Commitcomplete.

然后由研发人员通过HS_PASSPORT_RECOV表确认,向当前表中补回误删除的数据,至此闪回恢复成功。如果没有闪回特性,这样的恢复就或者需要通过物理备份进行不完全恢复,或者找出足够及时的逻辑备份来进行恢复,其过程都可能是极其复杂的。

【责任编辑:董书