Oracle的回收站和闪回查询机制(一)

来源:互联网 发布:java 多个list合并 编辑:程序博客网 时间:2024/04/28 21:20

实际工作中,我们经常会遇到一些情况,误删除某些表或某些表的某些记录,这时候就需要我们将这些记录重新插入进去。如何才能解决这个问题呢?

Oracle的Flashback query(闪回查询)为我们解决了这个问题 ,他的原理是Oracle根据undo信息,利用undo数据,类似一致性读取方法,可以把表置于一个删除前的时间点(或SCN),从而将数据找回。

下面我们先从简单的例子来看闪回查询的用法;

现有一张表有如下的数据


如果误执行了delete语句,删除其中一条记录,或插入一个废数据,修改了另外一个记录,

delete hb where 姓名 = '张三';
insert into hb (姓名, 语文, 数学, 物理) values ('王五', 99, 99, 99);
update hb set 语文 = '60', 数学 = '60', 物理 = '60' where 姓名 = '李四';

这些操作,此时得到了如下的数据


我现在希望以上的操作全部回退,回到这最初始的状态,此时就需要用到我们的Oracle提供的闪回查询,


上面的闪回是基于时间点的,前面也说了还可以基于SCN来查询,道理是一样的,


通过查询系统参数表,知道10点31分是28分的后面,所以我们查询的所依据的SCN则采用14119586030431;

SELECT hb.*, sysdate FROM hb AS OF scn 14119586030431;

一样可以得到上面的结果。这些都是查询修改前的数据记录,我们也可以直接将表整体闪回

 flashback table hb to scn 14119586030431;

注意此操作会修改表记录中的rowid,所以表必须允许行迁移
 alter table hb enable row movement;
这样,就可以将整个表闪回到原来的数据状态。

在此需要说明的是Oracle每5分钟记录一次SCN,并将SCN和对应时间的映射进行纪录。如果原来插入的记录到做闪回操作的时间在5分钟之内,用基于时间的闪回查询可能得不到记录,因为基于时间点的查询实际上是转化为最近的一次SCN,然后从这个SCN开始进行恢复。因此,如果需要精确的查询可以采用基于SCN的闪回查询,可精确闪回到需要恢复的时间。可以通过

SELECT DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER FROM DUAL;

获得系统当前的SCN。

(由于快照时间太久了,这上面我采用的新的SCN)这上面的是可以查看对应的时间段内对表所进行的操作:

versions_startscn,versions_starttime记录了操作时的SCN或时间,如果为空,表示在查询范围外创建的
versions_endscn,versions_endtime记录了失效时的SCN或时间,配合version_operation列查看,如果为空,或者被删除、或者该记录当前时间在当前表不存在
versions_operationI:insert     D:delete    U:update
versions_xid事务ID

以上这些都是表记录级别的闪回查询。知道了如何使用使用使用闪回查询,那么原理呢?

我们知道,在Oracle中数据都是存储在表空间中的,而闪回查询就是查询undo空间里的数据来实现的。

 回滚段(undo)用于存放数据修改之前的位置和值,回滚段的头部包含正在使用的该回滚段事务的信息。回滚段的作用如下: 
(1)事务回滚:当事务修改表中数据的时候,该数据修改前的值(即前影像)会存放在回滚段中,当用户回滚事务时,Oracle将会利用回滚段中的数据前影像来将修改的数据恢复到原来的值。 
(2)事务恢复:当事务正在处理的时候,例程失败,回滚段的信息保存在重做日志文件中,Oracle将在下次打开数据库时利用回滚来恢复未提交的数据。 
(3)读一致性:当一个会话正在修改数据时,其它的会话将看不到该会话未提交的修改。而且,当一个语句正在执行时,该语句将看不到从该语句开始执行后的未提交的修改(语句级读一致性)。这里就涉及到Oracle的事务级别,在此不做讨论。 

而Oracle的delete和commit操作的流程:
(1)delete流程 ,首先Oracle将数据块读到缓冲区中; 在“重做日志缓冲区”中记录delete操作的全过程;在相应回滚段段头的事务表中创建一个回滚条目;将要删除的记录创建前镜像并存放到回滚段中;最后将相应的数据块上删除记录并标记相应的数据块为dirty。 
(2)commit流程 ,Oracle产生一个SCN;在回滚段事务表中标记此事务为committed,然后日志读写进程将日志缓冲区中的记录写到日志文件。 

所以后面我们通过闪回读取的记录都是回滚段中记录的,换句话说,回滚段中有的数据我们可以通过闪回查询查出来,没有的数据的话就无法通过这个技术。


因此,要使用闪回查询,undo_management必须设置为AUTO,undo_retention是undo保存数据的时间,单位是秒,设置的越大,就需要更大的表空间来支持,undo_tablespace即时回滚表空间的名称。

0 0