谈Oracle中的回闪查询

来源:互联网 发布:分析软件有哪些 编辑:程序博客网 时间:2024/05/16 16:59

       人非圣贤,孰能无错。这一方面是说人人都会犯错,但另一方面,我们应该认识到这绝不能成为我们犯错的借口。可如果错误已经既成事实,我们还是会发自肺腑地企盼,“求求上天再给我一次机会吧!”。人人都知道,世上没有后悔药,但我说在Oracle中有,你相信吗?

 

       我们现在的开发工作几乎不能脱离数据库而存在,而在我们的项目中数据库则以Oracle居多,但人非圣贤,孰能无错,错误几乎是我们形影不离的朋友,像一个变量为定义,类型不匹配,参数不对等等,这些错误可以说不知碰到了多少次了,小问题,随手一改就OK了。然而要是数据库出了问题就严重了。如果仅仅是写错了一个Sql,导致执行的时候报错,倒也问题不大。但要是一切都顺利进行了,只是在进行业务操作的时候,我们误删除了一条记录,或修改了一条记录,我们可能就头痛了,最要命的是我们已经记不清数据更新前的记录是什么了。这时我们该怎么办呢?Oracle中有后悔药卖吗?
      有没有后悔药,这个我可不敢打保票,当然也不是说就一点希望也没有,有没有就要去问问你的DBA了。下面我就来谈谈这后悔药是什么,为什么还要去问DBA,这后悔药又如何服用。
     为了保证数据读取的一致性,Oracle中在查询显示数据的时候,只显示事务已经提交了的数据。我们在日常操作中如果意外地提交了一个错误的事务,比如像前面说的误删除或修改了一条记录,这时该怎么办呢?我们还能查询到事务提交前的数据吗?对在Oracle9i及之后的版本来说是可能的,那就是回闪查询。当然不是所有的数据库都支持回闪查询,要支持回闪查询必须使用系统管理的撤销功能,该功能在Oracle9i中引入,用来支持对回滚段的自动管理。DBA必须创建一个撤销表空间,启用自动撤销管理(Automatic Undo Management),并创建一个撤销保留时间窗,这样才能有效地进行回闪查询。所以你要去问问DBA在当前的环境中有没有该功能。
Oracle会在撤销表空间中维护足够多的撤销信息,以便在保留时间内支持回闪查询。能不能成功地执行回闪查询,在很大程度上取决于保留时间的设置以及撤销表空间的空间大小这两个因素。
        下面我们就来看一个实际工作中的具体案例(下面的操作我们都是在假“后悔”存在的前提下进行的)。
首先有一个物资表,有物资ID(MATERIAL_ID)、物资编号(MATERIAL_CODE)、物资名称(MATERIAL_NAME)三个字段,我们先对表中所有的记录进行查询,SQL语句如下所示:
select t.material_id,t.material_code,t.material_name 
 from tb_material t       ------------------ sql1
执行查询,我们得到如下的结果:
MATERIAL_ID
MATERIAL_CODE
MATERIAL_NAME
4
001
复合肥
5
002
除芽通
6
003
漂盘
表1
       接着错误发生了,业务人员不小心删除了复合肥这种物资,当然我们假设的这位业务人员记性很差,他想不起刚删除的物资是什么了,然后向我们求助。删除复合肥,在前台肯定就是点击一下“删除”按钮,而在后台则是相当于执行了如下的SQL语句:
delete from tb_material
 where material_id=4       
      这时,我们再执行sql1的SQL语句,得到的结果如表2所示:
MATERIAL_ID
MATERIAL_CODE
MATERIAL_NAME
5
002
除芽通
6
003
漂盘
表2
      毫无疑问,现在表中只有两种物资了,我们如何知道在一段时间前有些几种物资呢?当然,现在回闪查询就要闪亮登场了。我们可以使用select命令的as of tomestamp子句来指定Oracle回闪数据的程度。现写出回闪查询的SQL语句如下:
select count(*)                       
 from tb_material                    
    as of timestamp (sysdate - 5/1440)
      上面的SQL语句表示在查询在现在时刻5分钟之前时,物资表中存在几种物资。因为每天有1440分钟,所以“sysdate – 5/1440”语句就是表示5分钟之前的状态。那执行这句SQL,将得到如下结果:
COUNT(*)
3
表3
      从表3中可以看出在5分钟之前,还存在3种物资,当然如果删除物资的操作已经超过了5分钟,这里就只会显示2了,这时你就需要把5更改为10甚至100之类的更大的数字才能查询到你期望的结果。好,言归正传,既然在5分钟之前有3种物资,我们赶紧用如下的SQL语句找到丢失的物资。
select material_id,material_code,material_name
 from tb_material                             
    as of timestamp (sysdate - 5/1440)        
      执行这条SQL语句,你又将看到如表1的结果了。既然丢失的记录已经找到,剩下如何将其再还原到表中的工作也就不用我唠叨了。
 
      上面所说的案例,说明了如何使用系统的时间戳进行回闪查询,但这种办法对多表回闪只提供有限的支持,如果要进行更复杂的回闪查询时,就该考虑使用系统的更改号(SCN)了。限于篇幅,这里就不多阐述了,有兴趣的朋友可以多研究研究。
 
      当然除了使用回闪查询进行数据恢复之外,还可以用Data Pump Import执行数据库恢复,或执行物理数据库恢复来将表还原至delete操作之前的状态。不过像我们的数据库中,很多表都设置了Del_flag的标志,进行删除时,是假删除的,倒也避免了很多隐患,但也有部分业务并不是采用这种方式,这时进行了误操作,就得想想办法了。最后,像回闪查询这些办法,都是在问题已经发生了,才来亡羊补牢的,我们更多需要做的是,未雨绸缪,在业务逻辑性、完整性等方面多下功夫,防止问题的发生才是正道。
 
原创粉丝点击