服务器 频道

Oracle 10g更强大的回闪数据库功能

  【IT168 服务器学院】用一个简单的SQL语句将一个表或者整个数据库恢复到以前的某一点。
  
  除夕之夜,Acme银行的数据库管理员(DBA)John正在和他的朋友们一起狂欢,倒计时迎接新的一年的到来。就在子夜钟声敲响、人群欢呼之时,他的寻呼机突然响了。在银行的数据中心,在年末进行利息累机批处理簿记过程中发生了错误,所有的利息计算都不准确。幸好开发团队找出了错误所在,并开发一个应急纠正模块,但这一纠正模块不能恢复已经造成的破坏。部门经理问John是否有什么方法能往回倒一些时间,将数据库恢复至该批处理开始之前的状态,该批处理大约是在晚上11:00开始的。
  
  对于DBA们来说,这不是一件很熟悉的事吗?John的选择是什么呢?
  
  在Oracle数据库10g之前,John可能会做一个"时间点"恢复,来将数据库恢复至所希望的某一时刻的状态。不幸的是,银行的定期日常备份大约就是在那个时间开始,这就意味着他将不得不用接近24小时的有价值的归案日志来恢复数据库。
  
  Oracle9i数据库中提供的另一种选择是使用回闪查询特性来重建到晚上11:00为止的该表的各行,并手动生成一组不同的表。这一方法尽管理论上可行,但如果表的数量很大,则会变得不切合实际。
  
  幸运的是,John现在的数据库是Oracle数据库10g,所以他拥有更多的选择。
  
  回闪表
  
  让我们来看一下上面的情况。出问题的年末批处理可能仅影响少数表。例如,它可能仅用新的账户结余更新了ACCOUNTS表。如果确实是这种情况,则John可以使用回闪表特性,它会将一个表恢复到一个过去的时间点的状态。
  
  执行回闪表操作不需要特殊的设置。唯一的要求是表必须具有可移动的行--或者是在创建表时设置,或者是在以后利用 ALTER TABLE ACCOUNTS ENABLE ROW MOVEMENT语句设置。FLASHBACK TABLE语句从撤消段中(undo segment)读取该表的过去映像,并利用Oracle9i中引入的回闪查询重建表行。
  
  如果模式所有者之外的非DBA用户执行回闪表操作,她需要拥有对该表的SELECT、 DELETE、INSERT、ALTER和FLASHBACK权限,或者拥有等价的ANY TABLE系统权限。
  
  对于John来说,ACCOUNTS像以下的样子:
  
  ACCOUNT_NO  NUMBER(12),
  BALANCE   NUMBER(15,2)
  STATUS    CHAR(1)
  STATUS的列值通常为"A"(active,活动),但是当利息计算应用程序启动时,所有的账户均被冻结,此状态也被更新为"F"(frozen,冻结)。当对每一账户都计算了利息后,该状态被更新为"I"(interest applied,利息已计算)。
  
  下面是John用使用回闪表特性的步骤:
  
  他索要一个大概的时间点,在这一点上数据库必须被重新检查,答案是大约晚上11:00。
  
  他定义一个期望返回到的逻辑参考点。下面是他现在查询该表时所看到的内容:
  
  select status, count(*)
  from ACCOUNTS
  group by status;
  
     STATUS  COUNT(*)
     ------ --------
     I     27088
     F     19999
  
  该输出显示到目前为止已经有27 088个账户被处理(状态=I)。 此前的状态为"A",这不是John所希望返回的位置。所希望的逻辑参考点应该是所有账户的状态都为"F"的时间点。他必须恢复到所有账户状态都为"F"的状态,这大约发生于晚上11:00。
  
  他检查一个状态="I"的当前示例账户,以便为未来的校验测试设定一个基线:
  
  select account_no, balance
  from ACCOUNTS
  where status = ''I''
  and rownum < 2;
   ACCOUNT_NO  BALANCE
  -----------  --------
     21633  3913.49
  
  他发出这一语句将ACCOUNTS表恢复至那个时间:
  
  flashback table ACCOUNTS to timestamp
  to_timestamp (''12/31/2003 23:00:00'',''mm/dd/yyyy hh24:mi:ss'');
  
  瞧! 整个表被恢复到那个时间的状态了。只要撤消段中所保存的撤消数据允许,John便可以回闪到过去的某个时间点。John也可以不用时间标记(stamp),而是使用系统改变数目(system change number,SCN),如下所示:
  
  flashback table ACCOUNTS
  to SCN 9988653338;
  
  此表已被恢复至晚上11:00的状态,但这是不是所希望的时间点状态呢?John再次检查状态:
  
  select status, count(*)
  from ACCOUNTS
  group by status;
  
  STATUS  COUNT(*)
  ------  --------
  I       88
  F     46999
  
  仍然有88个记录的状态为"T"。所以,晚上11:00还不够早,John不得不返回到更早的一个时间点。他将该表回闪到更早的一个时间点上--晚上10:30--然后再次检查状态:
  
  flashback table ACCOUNTS to timestamp
  to_timestamp (''12/31/2003 22:30:00'',''mm/dd/yyyy hh24:mi:ss'');
  
  select status, count(*)
  from ACCOUNTS
  group by status;
  
  STATUS  COUNT(*)
  ------  --------
  A     47087
  
  John返回到的过去时间太远了些,所有账户的状态都为"A",这是"F"状态之前的一个状态。于是,他不得不向后滚动一段时间,滚动到晚上10:45。
  
  flashback table ACCOUNTS to timestamp
  to_timestamp (''12/31/2003 22:45:00'',''mm/dd/yyyy hh24:mi:ss'');
  
  select status, count(*)
  from ACCOUNTS
  group by status;
  
  STATUS  COUNT(*)
  ------  --------
  F     47087
  
  这正是他希望的时间点。他通过选择他以前查询过的账户来确证这一点。
  
  select balance
  from ACCOUNTS
  where account_no = 21633;
  
  BALANCE
  -------
  3836.75
  
  有效的结余为$3,913.49;返回到了晚上10:45的状态。至此操作完成。可以向前和向后应用任意次回闪操作,直到到达所期望的准确时间点的状态为止。
  
  由于此表永远不会被删除,所以所有的从属对象--如索引、约束条件、触发器等等--都会保持完好无损。引用此表的所有独立对象,如过程等,也都保持有效。即使是对分割表的全局索引也会保留,并保持有效。
  
  除了ACCOUNTS表之外,如果John还希望将TXN表回闪,那么他可以应用许多由逗号隔开的表名,如下所示:
  
  flashback table BANK.ACCOUNTS, bank.txn to scn 1234567;
  
  通过一个功能强大的SQL语句完成了整个回闪表操作。
  
  让我们来研究另一种情况。假设Laura意外地删除了一个关键字查询表--GL_MASTER。意识到这一错误后,她问John能否恢复这个表。在 Oracle数据库的以前一些版本中,这需要进行时间点恢复。但在Oracle数据库10g中,删除一个表只是将该表重命名后放置到称作"回收站"的逻辑容器中。
  
  为了恢复此表,John只发出了以下命令:
  
  flashback table gl_master to before drop;
  
  这个表马上就重新出现了,不需要任何恢复操作。请注意,与前面所描述的回闪操作不同,它不需要通过撤消段重建数据;而只是从回收站中将此表取回。
  
  回闪数据库
  
  如果说逻辑上的破坏不限于为数不多的几个表,那么利用Oracle 10g中的Flashback Database(回闪数据库)特性执行数据库时间点恢复可以使恢复更快一些。Flashback Database不需要利用撤消空间(undo space),而是利用硬盘上被称作快闪恢复区(flash recovery area)的另一区,它与撤消操作无关。Flashback Database允许进行数据库时间点恢复,而不要求你首先恢复你数据库的一个备份。
  
  要回闪整个数据库,John必须进行以下操作为数据库做准备,从而使其具有回闪能力:
  
  通过设置以下两个参数来配置一个大小为2GB的回闪区域:
  
  db_recovery_file_dest = /usr/users/oracle/10.1/recovery_area
  db_recovery_file_dest_size = 2G
  
  使用以下参数,以分钟为单位配置最大回闪时间:
  
  db_flashback_retention_target = 1440
  
  这一数值反映出可以返回的最大时间;实际可能的时间由快闪恢复区域的可用空间大小来决定。所以这三个参数都是动态的,并可以使用ALTER SYSTEM命令进行设置。
  
  使数据库能够回闪。为此,它必须处于archivelog模式下。在MOUNT阶段,在OPEN之前,John发出如下命令:
  
  alter database flashback on;
  
  在启动Flashback Database之后,它定期将已发生变化的块写入一个特殊类型的称作回闪日志的日志文件中。这些日志不是由传统的Log Writer (LGWR) 过程写入,而是由一种称作Recovery Writer (RVWR)的新过程写入。与常规的重做日志(redo logs)不同,回闪日志既不需要由DBA创建,也不需要由他们维护;它们由Oracle Managed Files(OMF)自动在快闪恢复区域所指定的目录中创建。这些文件不会归档,所以,如果在该目录发生介质故障后就不可能再进行恢复。
  
  回闪操作
  
  在所描述的Acme银行的事例中,John认为在他所处的情况下回闪表不太可行。他不得不将整个数据库回滚到过去的某个时间点。他再一次选择晚上11:00作为开始点,并发出以下命令:
  
  flashback database to timestamp
  to_timestamp (''12/31/2003
  23:00:00'',''mm/dd/yyyy hh24:mi:ss'');
  
  这一操作执行所有的必要任务,如使用来自快闪恢复区域中的信息恢复数据文件,并应用这些改变。现在整个数据库都回滚到其晚上11:00的状态。这里不再需要John执行任何手动恢复。John可以不使用时间标记,而使用SCN进行回闪。警报日志(代码清单1列举了其中某些部分)给出了回闪操作的一些相关信息。它清楚地给出该语句将数据文件恢复到指定SCN数目的状态所采取的一些步骤。
  
  尽管数据库被恢复到了晚上11:00的状态,但仍然存在一个问题--这是不是正确的时间点?John使用在"回闪表"部分提到的同一参考点方法。他以READ ONLY模式打开数据库,并选择状态,如下所示:
  
  alter database open read only;
  
  select status, count(*)
  from BANK.ACCOUNTS
  group by status;
  
  STATUS COUNT(*)
  ------ --------
  I       255
  F     46832
  
  如果有255个记录其状态为"I",这意味着他还必须返回得更远一些--至晚上10:30,如下所示:
  
  shutdown immediate
  startup mount
  
  flashback database to timestamp
  to_timestamp (''12/31/2003 22:30:00,
  ''mm/dd/yyyy hh24:mi:ss'');
  
  alter database open read only;
  
  在发出对ACCOUNTS的以下相同查询之后:
  
  select status, count(*)
  from BANK.ACCOUNTS
  group by status;
  
  他看到所有账户的状态为"A",这意味着他返回得太远了。他必须由该时间点向前移动一些--移至10:45,如下所示:
  
  shutdown immediate
  startup mount
  
  flashback database to timestamp
  to_timestamp (''12/31/2003 22:45:00,
  ''mm/dd/yyyy hh24:mi:ss'');
  
  alter database open read only;
  
  现在以下的状态查询:
  
  select status, count(*)
  from bank.accounts
  group by status;
  
  结果显示所有账户的状态均为"F":这就是所需要的准确的时间点位置。只要恢复区域具有必要的回闪日志,并且数据库是以只读模式打开的,那么John就可以来回滚动,以获得正确的时间点位置。现在John已经回闪到他所需要的确切时刻,他可以像下面这些打开数据库进行更新:
  
  shutdown immediate
  startup mount
  alter database open resetlogs;
  请注意,如果数据库是以排它(或只读)方式安装的,那么也可以通过Oracle恢复管理器 (Recovery Manager,RMAN)来完成回闪,如下所示:
  
  RMAN> flashback database to scn 2203167700;
  
  Starting flashback at 01-JAN-04
  allocated channel: ORA_DISK_1
  channel ORA_DISK_1: sid=10 devtype=DISK
  starting media recovery
  media recovery complete
  Finished flashback at 01-JAN-04
  
  对Flashback Database操作有几条限制。数据库不能回闪至通过RESETLOGS选项它被打开之前的时间点。
  
  如果未恢复或重新创建控制文件,如果已经删除了一个表空间,或者已缩小了一个数据文件。
  
  但是数据的扩展是通过回闪来处理的,所以由于自动扩展选项而发生的文件自动扩展不成为问题。
  
  估算恢复区域的大小
  
  当John在仔细考虑其选项时出现的一个问题是,他可以将数据库回闪到过去的什么时刻?他在两个视图中找到这一答案。第一个视图--V$FLASHBACK_ DATABASE_LOG显示出已经生成了多少回闪日志,并已经将其置于恢复区域中。下面是对该视图的查询,并以垂直格式显示这些列:
  
  select *
  from v$flashback_database_log;
  OLDEST_FLASHBACK_SCN   :2203146511
  OLDEST_FLASHBACK_TIME   :30-DEC-2003 18:37:09
  RETENTION_TARGET     :10000
  FLASHBACK_SIZE      :16384000
  ESTIMATED_FLASHBACK_SIZE :10857984000
  
  这表示John最多可以回闪至SCN2203146511或者2003年12月30日的下午06:37:09。根据初始化参数值 db_flashback_retention_target,当前预期的回闪保持时间为10 000分钟,但是保持这些多回闪日志的恢复区域大小最小应为列ESTIMATED_FLASHBACK_SIZE的数值。该恢复区域现在保存着 16384K字节的回闪信息(FLASHBACK_SIZE)。此估算值有助于John分配足够的恢复区域的空间,以获得很强的回闪能力。
  
  最终出现的另一个问题是,当数据库处于回闪模式时,此记录日志的操作需要多少空间。另一视图--V$FLASHBACK_DATABASE_STAT给出了到目前为止已经收集了多少回闪信息,如代码清单2所示。该视图给出了在由开始时间和终止时间所指定的1小时间隔内所记录的日志信息的总量。FLASHBACK DATA列给出在该时间间隔内已经产生了多少字节的回闪日志。所产生的重做(redo)日志项和发生了变化的数据块已经分别记录在REDO_DATA和DB_DATA中。这有助于理解回闪日志生产的本质和估算所需恢复区域的大小。
  
  如果不再需要回闪,那么John可以通过下面命令关闭它:
  
  alter database flashback off;
  
  在恢复区域所生成的所有OMF文件在回闪关闭时会自动被删除。John通过查询视图V$DATABASE中的FLASHBACK_ON列来验证数据库的回闪状态。
  
  SQL> select flashback_on
  from v$database;
  
  FLASHBACK_ON
  ------------
  NO
  
  结论
  
  Oracle 数据库10g中的回闪操作是从在Oracle9i中引入这种操作发展而来的,现已包含表级别的回闪和功能更强大的一些回闪操作,如回闪数据库,在这种操作下,可以将整个数据库恢复到过去的某一时间点。借助回闪功能,DBA可以变为一个精确的时间旅行者,可以准确控制所返回的时间,以及用怎样精细的时间间隔返回。
0
相关文章