加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Flashback Query

发布时间:2020-12-15 06:36:33 所属栏目:百科 来源:网络整理
导读:除夕之夜,Acme银行的数据库管理员(DBA)John正在和他的朋友们一起狂欢,倒计时迎接新的一年的到来。就在子夜钟声敲响、人群欢呼之时,他的寻呼机突然响了。在银行的数据中心,在年末进行利息累机批处理簿记过程中发生了错误,所有的利息计算都不准确。幸好
除夕之夜,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,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);

TIMESTAMP的查询方式

SELECT * FROM table_name AS OF TIMESTAMP sysdate-2/1440? --查询2分钟之前的数据

SELECT * FROM table_name AS OF TIMESTAMP to_timestamp('2011-11-18 12:00:00','yyyy-mm-dd hh24:mi:ss');

当通过TIMESTAMP 来查询历史数据时,数据库会吧TIMESTAMP转换成SCN。

--查看SCN 和TIMESTAMP 的对应关系
?????? select scn,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss')
?????? from sys.smon_scn_time
?????? order by scn;
  回闪版本查询 SELECT versions_startscn,versions_starttime,versions_endscn,versions_endtime,versions_xid,versions_operation FROM test VERSIONS BETWEEN TIMESTAMP systimestamp -10/1440 and systimestamp; SELECT versions_startscn,versions_operation FROM test VERSIONS BETWEEN TIMESTAMP TO_TIMESTAMP('2011-11-18 9:00:00','yyyy-mm-dd hh24:mi:ss') AND TO_TIMESTAMP('2011-11-18 15:38:30','YYYY-MM-DD HH24:MI:SS'); SELECT ID,VL,VERSIONS_STARTSCN,VERSIONS_ENDSCN,? VERSIONS_OPERATION,VERSIONS_XID ? FROM test VERSIONS BETWEEN SCN 1273892 AND 1273922; ? select * from test versions between timestamp systimestamp -10/1440 and systimestamp; DDL查询 ----------------------------------------------------------------- SELECT ? OBJECT_NAME,                        --对象名?       OBJECT_TYPE,                        --对象类型?       TO_CHAR(CREATED,? 'YYYY-Mon-DD ? HH24:MI ') ? CREATE_TIME, --创建时间?       TO_CHAR(LAST_DDL_TIME,? 'YYYY-Mon-DD ? HH24:MI ') ? MOD_TIME,   ? --修改时间?       TIMESTAMP,                         --时间戳?       STATUS                           --状态?   FROM ? USER_OBJECTS?   ?  WHERE ? to_char(LAST_DDL_TIME,'yyyymmdd ')> '&日期变量 ';

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读