Oracle闪回查询

闪回查询包括基本的闪回查询、闪回表、闪回版本查询、闪回事务查询。

 

闪回查询允许查询过去某个时间点的数据库,它可以借助于一条select语句或通过将会话临时回退到过去以使其所有查询都针对先前版本的数据库来进行。此功能可以用来查看在提交一组事务之前表的数据状态。半小时之前的表的状态是怎样的呢?通过闪回查询,可以找出数据对比。利用它还可以选取过去一段时间内一个行的所有版本记录,从而清楚的了解该行上的历史操作,包括操作时间、操作人和作出每个更改的事务标识符。

 

一旦确认了引起问题的事务,Oracle可以自动构造SQL语句来反转事务的更改,自动执行修复过程。这不是回滚一个已提交的事务,因为关系数据库的规则是不允许这么做的。但可以构造另一个事务来反转前一个事务造成的影响。与闪回数据库不同的是,闪回事务不会丢失数据,所做的其它工作仍然保留,并且数据库可以保持当前状态。

 

闪回表则是如果已经确定针对某个表提交了不正确的操作,可以指示Oracle反转从特定时间点以来对该表所做的所有更改,而其它表保持当前状态不变。

 

在执行任何闪回查询、闪回事务或闪回表操作期间,数据库保持打开状态,并且所有对象(包括闪回中涉及的对象)都是可以使用的。闪回过程可能需要取消对某些表的完整性和约束的强制检查,否则闪回操作可能失败。如一个事务的闪回要求对主键列执行插入操作,那么该键值必须不在当前表中。又如一个表有外键约束,那么不能对该表单独执行闪回操作,而必须在一个操作中闪回所有相关的表。

 

相比于闪回数据库,各种形式的闪回查询具有更精细的恢复粒度,应该不会对用户造成任何影响。除了需要授予适当的权限外,不需要任何配置即可使用。各种形式的闪回查询只依赖于撤销表空间的使用,可能要求对撤销管理做一些调整。所有形式的闪回查询都是依赖于撤销表空间数据来重构它在过去某个时间点的数据。闪回查询可以回退到多久以前取决于撤销表空间中是否有撤销数据可用,如果构造过时的结果则查询将会失败。

 

1、基本的闪回查询

 

闪回查询的语法接受时间戳或SCN的形式。可以查询以前某个时间点的数据库,但不能对过去版本的数据执行DML操作。以下示例说明了闪回查询的基本用法,并利用闪回查询恢复了被删除的数据。

 

1)看一下当前时间

select sysdate from dual;

 

SYSDATE

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

2016-03-14 22:44:57

 

2)连接到cmes用户,删除表c_line_t中的一些数据

conn cmes/cmes

select line_id, line_name from c_line_t;

 

   LINE_ID LINE_NAME

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

       120 维修

        80 MZ前悬左

       100 MZ副车架

     19540 MZ前悬右

     35960 MZ前减

     86360 MZ后桥

     87360 MZ后减

     87740 MZ后角

 

delete from c_line_t where line_name like 'MZ%';

commit;

select line_id, line_name from c_line_t;

 

   LINE_ID LINE_NAME

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

       120 维修

 

3)闪回查询历史数据

select line_id, line_name from c_line_t as of timestamp to_timestamp('2016-03-14 22:44:50', 'yyyy-mm-dd hh24:mi:ss');

 

   LINE_ID LINE_NAME

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

     19540 MZ前悬右

     87740 MZ后角

     35960 MZ前减

        80 MZ前悬左

       100 MZ副车架

       120 维修

     87360 MZ后减

     86360 MZ后桥

 

4)插入被删记录,确认数据恢复

insert into c_line_t (select * from c_line_t as of timestamp to_timestamp('2016-03-14 22:44:50', 'yyyy-mm-dd hh24:mi:ss') minus select * from c_line_t);

commit;

select line_id, line_name from c_line_t;

 

有时我们还希望能将整个会话回退到过去某个时间点来完成一系列的历史查询,这可以通过使用dbms_flashback程序包来完成,它可以将整个会话设定为闪回模式

exec dbms_flashback.enable_at_time(to_timestamp('2016-03-05 15:14:15', 'yyyy-mm-dd hh24:mi:ss'));

 

从此以后,该会话所有的查询将停留在指定的时间点上,而其它会话不受影响。如果需要取消这一设定,可以执行以下命令

exec dbms_flashback.disable;

 

闪回查询的另外一种形式是基于SCN

select count(*) from c_line_t as of scn <SCN>;

 

SCN可以借助视图v$archived_log参考历史时间段确定

col name for a80

select name, first_change#, next_change#, first_time from v$archived_log;

 

2、闪回表操作

 

表的闪回操作是一个单独的事务,它试图抵消以前事务的效果,这并不是去回滚已经提交的事务,关系数据库的规则不允许这么做,而只能是用一个新事务来取消已提交工作的影响。

 

闪回表操作维护所有的索引并强制执行约束,唯一不同之处,表上的触发器对闪回操作默认是禁用的。表的闪回经常会涉及到存在外键关系的表,在这种情况下,几乎不可避免的是闪回操作会因为违反约束而失败。为解决此问题,语法支持用一条闪回命令闪回多个表,这将作为单个事务来执行,并在最后检查约束。

 

表闪回的第一步是启用表的行移动功能,这在数据字典中是通过设置标志来通知Oracle可能改变了行ID。一条记录的行ID实际上是永远不会变的,但闪回操作使它看起来好像变了。

 

以下举例说明闪回表的操作:

 

1)在MES数据库里我们先为Oracle默认安装时自带的scott模式解锁,这将可以连接到scott用户,并看到其下有几张表

sqlplus / as sysdba

alter user scott identified by tiger account unlock;

conn scott/tiger

select * from cat;

 

TABLE_NAME                     TABLE_TYPE

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

BONUS                          TABLE

DEPT                           TABLE

EMP                            TABLE

SALGRADE                       TABLE

 

这里员工表EMP和部门表DEPT之间存在外键关系,就是说EMP表中的每个员工必定是部门表DEPT中某个部门的成员。

col constraint_name for a20

col table_name for a20

col r_constraint_name for a20

select constraint_name, constraint_type, table_name, r_constraint_name, status from user_constraints where table_name = 'EMP';

 

CONSTRAINT_NAME      CON TABLE_NAME           R_CONSTRAINT_NAME    STATUS

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

PK_EMP               P   EMP                                       ENABLED

FK_DEPTNO            R   EMP                  PK_DEPT              ENABLED

 

2)在部门表DEPT中新增一个部门,并在员工表中添加一名员工属于该部门,之后看一下时间

insert into dept values(50, 'AUTOMATION', 'NANJING');

commit;

insert into emp values(8001, 'LIULUNING', 'MANAGER', 7698, '2012-05-01', 4000, 0, 50);

commit;

select sysdate from dual;

 

SYSDATE

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

2016-03-19 15:27:38

 

3)删除该部门和员工,要注意应首先删除员工再删除部门,以避免违反约束

delete from emp where empno = 8001;

delete from dept where deptno = 50;

commit;

 

4)尝试将表闪回到该部门及其员工存在的时刻

flashback table emp to timestamp to_timestamp('2016-03-19 15:27:38', 'yyyy-mm-dd hh24:mi:ss');

 

...

ORA-08189: 因为未启用行移动功能, 不能闪回表

 

操作失败,因为没有开启行移动,这是表闪回的前提条件。于是为两个表启用行移动功能

alter table dept enable row movement;

alter table emp enable row movement;

 

5)重新尝试闪回

flashback table emp to timestamp to_timestamp('2016-03-19 15:27:38', 'yyyy-mm-dd hh24:mi:ss');

 

...

ORA-02091: 事务处理已回退

ORA-02291: 违反完整约束条件 (SCOTT.FK_DEPTNO) - 未找到父项关键字

 

由于违反了外键约束,闪回仍然不能成功。要避免该问题,可以先闪回部门表DEPT,这样可以插入50部门,然后再闪回员工表EMP,就不会违反约束了。但是,如果闪回涉及多个表和许多DML语句,那么在逻辑上可能很难找到一个有效的顺序。为此,Oracle提供的解决办法就是允许同时闪回多张表

flashback table emp, dept to timestamp to_timestamp('2016-03-19 15:27:38', 'yyyy-mm-dd hh24:mi:ss');

 

这样闪回可以成功,因为这是在一个事务中同时闪回了两张表,Oracle仅在该事务的结尾检查约束,此时数据在逻辑上已经一致。

 

实际中,闪回操作也可能由于其它原因而失败:

  • 如果在删除和闪回之间重用了键值,就会出现主键约束;
  • 如果没有足够的撤销信息返回到请求的时间;
  • 如果其他用户锁定闪回作用的任何行;
  • 闪回不能跨越表的一些DDL操作,如删除了一列、对表做了截断,都是无法闪回的;
  • 闪回不适用于SYS模式下的表,试想一下闪回部分数据字典将会怎样。

 

如果闪回因为任何原因而失败,Oracle就会取消闪回操作,回滚已经成功执行的任何一部分操作,将表处于闪回命令发出之前的状态。

 

闪回表语法的变型允许闪回到一个系统变更号,并在操作期间激活DML触发器,而不是默认的禁用状态

flashback table emp, dept to scn 6539425 enable triggers;

 

3、闪回版本查询

 

一个行在它的生命周期内可能改变多次。闪回版本查询允许查看一个行所有提交过的版本,包括创建和结束每个版本的时间戳。另外还可以查看创建了任何特定版本行的事务标识符,它可以用于闪回事务查询。

 

这些信息是通过每个表的许多伪列来提供的。与闪回相关的伪列包括:

  • versions_startscn:通过insert或update创建此版本行的scn;
  • versions_starttime:创建此版本行的时间戳;
  • versions_endscn:由于delete或update使此版本行失效的scn;
  • versions_endtime:此版本行失效的时间戳;
  • versions_xid:创建此版本行的事务的唯一标识符;
  • versions_operation:创建此版本行的事务执行的操作,可以是insert、update或delete。

 

为了查看这些伪列,必须在查询中包含versions between关键字,并使用两个常量来表示scnminvalue指示Oracle检索撤销表空间中最早的信息,maxvalue将作为当前的scn

select empno, ename, sal, versions_xid, versions_starttime, versions_endtime, versions_operation from emp versions between scn minvalue and maxvalue;

 

     EMPNO ENAME             SAL VERSIONS_XID     VERSIONS_STARTTIME             VERSIONS_ENDTIME            V

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

      8020 YAOWEI           3500 05000F00FC050000 19-3 -16 05.41.54 下午                                   D

      8020 YAOWEI           3500 080011006D060000 19-3 -16 05.41.33 下午       19-3 -16 05.41.54 下午            I

      8000 LIULUNING        5000 05000400FB050000 19-3 -16 05.40.09 下午                                   U

      8000 LIULUNING        4000                                                 19-3 -16 05.40.09 下午

      7369 SMITH             800

      7499 ALLEN            1600

      7521 WARD             1250

      7566 JONES            2975

      7654 MARTIN           1250

      7698 BLAKE            2850

      7782 CLARK            2450

      7788 SCOTT            3000

      7839 KING             5000

      7844 TURNER           1500

      7876 ADAMS            1100

      7900 JAMES             950

      7902 FORD             3000

      7934 MILLER           1300

 

版本查询结果是按照时间降序排列的,应当自下而上理解:

闪回到撤销表空间保留的最早记录,编号为8000的员工,在1631917:40:09之前SAL值为4000,之后对表做了update操作(versions_operation伪列表示为“U”),SAL值更新为5000。在17:41:33时刻对表做了一次插入操作(versions_operation伪列表示为“I”),新增了编号为8020的员工,该版本状态延续到17:41:54时刻,该条新增的记录又被删除(versions_operation伪列表示为“D”)。versions_xid伪列则记录了每个事务的事务标号。

 

闪回版本查询的语法也接受使用两个时间戳来指定时间范围,如查看最近一小时内员工编号为8000的所有版本:

select empno, ename, sal, versions_xid, versions_starttime, versions_endtime, versions_operation from emp versions between timestamp(systimestamp - 1/24) and systimestamp where empno = 8000;

 

闪回版本查询不能用于外部表、临时表或v$视图,原因是这些对象都不生成撤销数据。当对表做了截断操作,或者对表栏做了删除列的操作后,闪回版本查询信息将丢失,但增加列的DDL操作则不会丢失版本查询信息。

 

4、闪回事务查询

 

闪回事务查询从事务的另外一个角度去考虑撤销数据:从闪回版本查询中我们可以看到一个表中某行数据的变化版本及其对应的事务标识。但是,如果一个事务还影响了其它表中的其它行,又如何去跟踪呢?闪回事务查询就是要考虑一个事务可能对所有表数据产生的影响,为此,Oracle提供了视图flashback_transaction_query,利用它可以看到受该事务影响的每个行都对应有一行记录。

desc flashback_transaction_query

Name             Type           Nullable Default Comments                                 

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

XID              RAW(8)         Y                事务标识符,是闪回版本查询中显示的versions_xid伪列的连接列,

       where xid = hextoraw('…')                

START_SCN        NUMBER         Y                事务开始时的系统变更号

START_TIMESTAMP  DATE           Y                事务开始时的时间戳

COMMIT_SCN       NUMBER         Y                事务提交时的系统变更号

COMMIT_TIMESTAMP DATE           Y                事务提交时的时间戳

LOGON_USER       VARCHAR2(30)   Y                执行事务会话的Oracle用户名

UNDO_CHANGE#     NUMBER         Y                撤销系统变更号               

OPERATION        VARCHAR2(32)   Y                应用到行的DML操作:insert update delete

TABLE_NAME       VARCHAR2(256)  Y                行所属的表

TABLE_OWNER      VARCHAR2(32)   Y                表所属模式

ROW_ID           VARCHAR2(19)   Y                受影响行的rowid

UNDO_SQL         VARCHAR2(4000) Y                反转操作的SQL语句

 

该视图会显示撤销数据仍保留在撤销段内的已提交的事务以及进行中的事务。查询该视图需要授予select any transaction的权限。对于活动的事务来说,COMMIT_SCNCOMMIT_TIMESTAMP列都是NULL,因为还没有提交。对于已回滚的事务则不会显示。由于这里XID列是RAW类型的,而版本查询中versions_xid伪列是十六进制的,因此查询时必须使用类型转换。另外,要想在查询中显示出UNDO_SQL反转SQL语句是有条件的,数据库必须开启补充日志(Supplemental Log)。下面的例子将会说明闪回事务查询的使用。

 

1)我们利用MES数据库里scott用户的表emp,并再创建一张表emp1和一个触发器tri_emp,该触发器负责对emp表的每行update操作在emp1中做同步更新

sqlplus scott/tiger

create table emp1 as select * from emp;

 

触发器代码如下:

create or replace trigger tri_emp

    after update on emp

    for each row

begin

    update emp1

       set ename    = :new.ename,

           job      = :new.job,

           mgr      = :new.mgr,

           hiredate = :new.hiredate,

           sal      = :new.sal,

           comm     = :new.comm,

           deptno   = :new.deptno

     where empno = :new.empno;

end;

 

2)查看数据库补充日志是否开启,查询反转SQL需要开启补充日志,这个需要登录到DBA下操作

sqlplus / as sysdba

select supplemental_log_data_min from v$database;

 

SUPPLEME

--------

NO

 

显示NO表示没有开启,现在开启补充日志

alter database add supplemental log data;

 

若要关闭补充日志,则使用以下语句

alter database drop supplemental log data;

 

补充日志也是记录在联机redo日志中的,所以启用补充日志会加快联机redo日志的填充。

 

3)在scott模式下对emp表插入一名编号为8020的新员工信息,并试图更新将编号为8000员工的工资增加10%,但误写为乘上10,并做了提交

insert into emp values(8020, 'YAOWEI', 'MANAGER', 7698, '2016-03-20', 4500, NULL, 50);

commit;

update emp set sal = sal * 10 where empno = 8000;

commit;

 

4)之后发现了错误,利用闪回版本查询查看表的历史变更:

select empno, ename, sal, versions_operation, versions_xid from emp versions between scn minvalue and maxvalue;

 

     EMPNO ENAME             SAL V VERSIONS_XID

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

      8000 LIULUNING       50000 U 06001400DC050000

      8020 YAOWEI           4500 I 0800210083060000

      8000 LIULUNING        5000

      7369 SMITH             800

      7499 ALLEN            1600

      7521 WARD             1250

      7566 JONES            2975

      7654 MARTIN           1250

      7698 BLAKE            2850

      7782 CLARK            2450

      7788 SCOTT            3000

      7839 KING             5000

      7844 TURNER           1500

      7876 ADAMS            1100

      7900 JAMES             950

      7902 FORD             3000

      7934 MILLER           1300

 

从下往上看,首先是做了一个8020员工的插入操作,之后对8000员工做了数据更新,SAL值由原来的5000更新为50000,并显示出了DML操作的事务号。

 

5)授予scott用户闪回事务查询的权限

grant select any transaction to scott;

 

6)根据上面版本查询中找到的事务号,执行闪回事务查询,看看这个错误操作可能影响到的所有表数据,并找到反转对冲语句

col operation for a10

col table_name for a10

col table_owner for a10

col undo_sql for a100

select operation, table_name, table_owner, undo_sql from flashback_transaction_query where xid = hextoraw('06001400DC050000');

 

OPERATION       TABLE_NAME      TABLE_OWNER     UNDO_SQL

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

UPDATE          EMP1            SCOTT           update "SCOTT"."EMP1" set "ENAME" = 'LIULUNING', "JOB" = 'MANAGER', "MGR" = '769

                                                8', "HIREDATE" = TO_DATE('2012-05-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss'), "SAL"

                                                = '5000', "COMM" = NULL, "DEPTNO" = '50' where ROWID = 'AAASaOAAEAAAAC7AAA';

 

UPDATE          EMP             SCOTT           update "SCOTT"."EMP" set "SAL" = '5000' where ROWID = 'AAAR3sAAEAAAACWAAA';

 

结果发现,对emp表的这个更新事务除了改变了自身数据,还影响到emp1表的数据变更,原因是触发器的作用。

 

7)利用上述查询中提供的反转对冲语句,我们可以纠正之前的操作。可以全部执行这些反转,或者因为我们明白触发器的作用,只需执行对emp表的更新,将所有数据修复回来

update "SCOTT"."EMP" set "SAL" = '5000' where ROWID = 'AAAR3sAAEAAAACWAAA';

commit;

 

视图flashback_transaction_query通过构造撤销语句来取消事务,但是对于大型事务而言,单个的执行它们是一项繁重的任务。这种情况下可以使用dbms_flashback程序包,它含有取消事务的过程,操作起来更加方便。它需要授予flashback any table的权限。我们可以在sysdba下执行操作

exec dbms_flashback.transaction_backout(numtxns=>2, xids=>sys.xid_array('0500130019060000', '02000E00CB050000'), options=>dbms_flashback.cascade);

 

该过程接受的参数说明:

  • numtxns:需要取消的事务的数量
  • xids:由闪回版本查询可以获得的事务标识符的一个列表,形如sys.xid_array('…', '…')
  • options:有四种常量选择
    • cascade,试图在逻辑上取消事务,因此不会出现约束违规
    • nocascade(默认值),应用撤销更改并且不尝试识别依赖关系,如果存在外键约束关系的表,操作很可能失败
    • nonconflict_only,只取消没有引起问题的行的更改,数据库仍保持一致,但是一些事务可能不完整
    • nocascade_force,将按照与提交时相反的次序撤销SQL语句

 

注意dbms_flashback.transaction_backout会将完成的各种撤销更改都保留为未提交状态,这样可以提供用户一个机会来确认完成的操作,确认无误后用户再提交更改。


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28974745/viewspace-2139605/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/28974745/viewspace-2139605/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值