--==================================================
-- Oracle 闪回特性 (Flashback Query 、 Flashback Table)
--==================================================
Oracle 闪回查询是指针对特定的表来查询特定的时间段内的数据变化情况来确定是否将表闪回到某一个特定的时刻以保证数据无讹误存在。
这个特性大大的减少了采用时点恢复所需的工作量以及数据库脱机的时间。 闪回查询通常分为 Flashback Query ( 闪回查询 ) ,
Flashback Table Query( 闪回表查询 ) , Flashback Version Query( 闪回版本查询 ) , Flashback Transaction Query( 闪回事务查询 ) 。本文主要讲
述 Flashback Query ( 闪回查询 ) , Flashback Table Query( 闪回表查询 ) 。其余闪回请参考后续文章。
一、 Flashback Query ( 闪回查询 )
通常用于检索一条记录的所有版本,倒退单独的事务或者倒退从指定时间以来对特定表的所有变化
Flashback Query 的所有形式取决于 UNDO 表表空间,关于 UDNO 表空间请参考: Oracle 回滚(ROLLBACK) 和撤销(UNDO)
1. 闪回查询 ( Flashback Query ) 语法
SELECT < column_name_list >
FROM < table_name >
AS OF < SCN > -- 使用 as of scn
[WHERE <filter_conditions>]
[GROUP BY <unaggregated columns>]
[HAVING <group_filter>]
[ORDER BY <column_positions_or_name>]
SELECT < column_name_list >
FROM < table_name >
AS OF < TIMESTAMP > -- 使用 as of timestamp
[WHERE <filter_conditions>]
[GROUP BY <unaggregated columns>]
[HAVING <group_filter>]
[ORDER BY <column_positions_or_name>]
2. 演示闪回查询
a . 演示使用 as of timestamp 来进行闪回查询
flasher@ORCL11G > create table tb1 as
2 select empno , ename , job , deptno from scott . emp where 1 = 0 ;
flasher@ORCL11G > insert into tb1
2 select empno , ename , job , deptno
3 from scott . emp where empno in( 7369 , 7499 , 7521 , 7566 );
flasher@ORCL11G > commit ;
flasher@ORCL11G > select * from tb1 ;
EMPNO ENAME JOB DEPTNO
---------- ---------- --------- ----------
7369 SMITH CLERK 20
7499 ALLEN SALESMAN 30
7521 WARD SALESMAN 30
7566 JONES MANAGER 20
flasher@ORCL11G > select to_char ( sysdate , 'yyyy-mm-dd hh24:mi:ss' ) from dual ;
TO_CHAR ( SYSDATE , 'YY'
-------------------
2010 - 10 - 25 17 : 26 : 08
flasher@ORCL11G > delete from tb1 where job = 'SALESMAN' ;
flasher@ORCL11G > commit ;
flasher@ORCL11G > select * from tb1 ;
EMPNO ENAME JOB DEPTNO
---------- ---------- --------- ----------
7369 SMITH CLERK 20
7566 JONES MANAGER 20
flasher@ORCL11G > select * from tb1 as of timestamp
2 to_timestamp ( '2010-10-25 17:26:08' , 'yyyy-mm-dd hh24:mi:ss' );
EMPNO ENAME JOB DEPTNO
---------- ---------- --------- ----------
7369 SMITH CLERK 20
7499 ALLEN SALESMAN 30
7521 WARD SALESMAN 30
7566 JONES MANAGER 20
flasher@ORCL11G > select * from tb1 as of timestamp
2 to_timestamp ( '2010-10-25 17:26:08' , 'yyyy-mm-dd hh24:mi:ss' )
3 minus select * from tb1 ;
EMPNO ENAME JOB DEPTNO
---------- ---------- --------- ----------
7499 ALLEN SALESMAN 30
7521 WARD SALESMAN 30
b . 演示使用 as of scn 来进行闪回查询
flasher@ORCL11G > select current_scn from v$database ;
CURRENT_SCN
-----------
2032782
flasher@ORCL11G > select * from tb1 ;
EMPNO ENAME JOB DEPTNO
---------- ---------- --------- ----------
7369 Henry CLERK 20
7566 JONES MANAGER 20
flasher@ORCL11G > delete from tb1 where empno = 7369 ;
flasher@ORCL11G > commit ;
flasher@ORCL11G > select * from tb1 as of scn 2032782 ;
EMPNO ENAME JOB DEPTNO
---------- ---------- --------- ----------
7369 Henry CLERK 20
7566 JONES MANAGER 20
由以上可知,通过闪回查询获得所需的记录信息,然后来构造新的 DML 语句并实施其操作来保证数据的完整性。
二、 Flashback Table Query ( 闪回表查询 )
通过查询 UNDO 段来抽取所有已变化的记录细节,在此基础之上再构造和执行能够倒退这些变化的语句
表闪回通过执行倒退变化的语句并且该执行是一个事务,所有常用规则在该事务上起作用。
表闪回时,表上的触发器缺省被禁用,即该表上的 DML 触发器将暂时失效,可以在闪回时指定触发器是否失效。
表闪回需要启用表上的记录转移选项
1. 下面给出表闪回的种方式
FLASHBACK TABLE < schema_name . table_name >
TO SCN < scn_number > -- 基于 SCN 的表闪回
[<ENABLE | DISABLE> TRIGGERS]
FLASHBACK TABLE < schema_name . table_name >
TO TIMESTAMP < timestamp > -- 基于 TIMESTAMP 的表闪回
[<ENABLE | DISABLE> TRIGGERS]
FLASHBACK TABLE < schema_name . table_name >
TO RESTORE POINT < restore_point > -- 基于 RESTORE POINT 的表闪回
[<ENABLE | DISABLE> TRIGGERS]
2. 演示基于 SCN 的表闪回
下面的演示首先创建表 tb_tables ,并对表分几次插入数据,在完成插入前记录其 SCN 号用于后续对其进行闪回
create table tb_emp as -- 创建演示表 tb_emp
select empno , ename , job , deptno from scott . emp where 1 = 0 ;
select table_name , row_movement from user_tables ; -- 查看表的 row movement 行为,缺省为 disable
TABLE_NAME ROW_MOVE
------------------------------ --------
TB_EMP DISABLED
select current_scn , systimestamp from v$database ; -- 获取系统当前的 SCN
CURRENT_SCN SYSTIMESTAMP
----------- --------------------------------------
661490 01 - JAN - 11 10.56.28.733000 PM + 08 : 00
insert into tb_emp -- 插入 deptno 为 10 的员工
select empno , ename , job , deptno from scott . emp where deptno = 10 ;
commit ;
select current_scn , systimestamp from v$database ; -- 获取系统当前的 SCN
CURRENT_SCN SYSTIMESTAMP
----------- --------------------------------------
661510 01 - JAN - 11 10.56.56.546000 PM + 08 : 00
insert into tb_emp -- 插入 deptno 为 20 的员工
select empno , ename , job , deptno from scott . emp where deptno = 20 ;
commit ;
select current_scn , systimestamp from v$database ; -- 获取系统当前的 SCN
CURRENT_SCN SYSTIMESTAMP
----------- --------------------------------------
661521 01 - JAN - 11 10.57.17.358000 PM + 08 : 00
insert into tb_emp -- 插入 deptno 为 30 的员工
select empno , ename , job , deptno from scott . emp where deptno = 30 ;
commit ;
select current_scn , systimestamp from v$database ; -- 获取系统当前的 SCN
CURRENT_SCN SYSTIMESTAMP
----------- --------------------------------------
661539 01 - JAN - 11 10.57.37.843000 PM + 08 : 00
select deptno , count (*) from tb_emp group by deptno order by 1 ;
DEPTNO COUNT (*)
---------- ----------
10 3
20 5
30 6
flashback table tb_emp to scn 661521 ; -- 将表闪回到 scn 为,即插入部门号为的记录之前
flashback table tb_emp to scn 661521 -- 闪回失败,收到错误提示,没有开启 row movement
*
ERROR at line 1 :
ORA - 08189 : cannot flashback the table because row movement is not enabled
alter table tb_emp enable row movement ; -- 开启表 tb_emp 表的 row movement 功能
flashback table tb_emp to scn 661521 ; -- 再次实施闪回,闪回成功
select deptno , count (*) from tb_emp group by deptno order by 1 ; -- 记录中没有部门为 30 的记录
DEPTNO COUNT (*)
---------- ----------
10 3
20 5
flashback table tb_emp to scn 661510 ; -- 将表闪回到 scn 为,即插入部门号为 20 的记录之前
select deptno , count (*) from tb_emp group by deptno order by 1 ; -- 记录中没有部门为 20 的记录
DEPTNO COUNT (*)
---------- ----------
10 3
3. 演示基于 TIMESTAMP 的表闪回
使用 to timestamp 进行表闪回 , 继续使用上面创建的表来进行闪回
-- 使用 timestamp 将表闪回到插入部门号 10 为之前
flashback table tb_emp to timestamp to_timestamp ( '01-JAN-11 10.56.28.733000' );
flashback table tb_emp to timestamp to_timestamp ( '01-JAN-11 10.56.28.733000' ) -- 收到错误提示
*
ERROR at line 1 :
ORA - 01466 : unable to read data - table definition has changed -- 表结构发生改变
flasher@ORCL11G > flashback table tb_emp to scn 661539 ; -- 可以将表闪回到插入部门号为 30 的记录之后
Flashback complete .
此处演示中收到了错误提示,注意对于表闪回,可以多次使用同一类型的闪回方式,可以往前闪回,一旦往前闪回之后,也可以往后进行闪回。
但交叉闪回则提示表定义发生了变化。闪回失败。我们可以再次创建一张类似的新表进行基于 timestamp 进行闪回,与闪回 SCN 说不同的
是,此处使用了 timestamp, 此演示在此省略。
4. 演示基于 RESTORE POINT 的表闪回
基于 RESTORE POINT 的表闪回首先要创建适当的闪回点,创建闪回点的方式为
CREATE RESTORE POINT point_name ;
对于闪回成功之后,无用的闪回点可以及时删除掉,删除闪回点的方式为
DROP RESTORE POINT point_name
下面对基于 RESTORE POINT 闪回进行演示
drop table tb_emp purge ; -- 删除先前创建的表 tb_emp
create table tb_emp -- 创建演示表 tb_emp
enable row movement
as select empno , ename , job , deptno from scott . emp where 1 = 0 ;
create restore point zero ; -- 创建闪回点 zero
insert into tb_emp -- 插入 deptno 为 10 的员工
select empno , ename , job , deptno from scott . emp where deptno = 10 ;
commit ;
create restore point one ; -- 创建闪回点 one
insert into tb_emp -- 插入 deptno 为 20 的员工
select empno , ename , job , deptno from scott . emp where deptno = 20 ;
commit ;
create restore point two ; -- 创建闪回点 two
insert into tb_emp -- 插入 deptno 为 30 的员工
select empno , ename , job , deptno from scott . emp where deptno = 30 ;
commit ;
select deptno , count (*) from tb_emp group by deptno order by 1 ;
DEPTNO COUNT (*)
---------- ----------
10 3
20 5
30 6
flashback table tb_emp to restore point two ; -- 闪回到闪回点 two 之前
select deptno , count (*) from tb_emp group by deptno order by 1 ;
flashback table tb_emp to restore point one ; -- 闪回到闪回点 one 之前
select deptno , count (*) from tb_emp group by deptno order by 1 ;
DEPTNO COUNT (*)
---------- ----------
10 3
drop restore point two ; -- 删除创建的闪回点
drop restore point one ;
drop restore point zero ;
5. 存在参照关系的表闪回
帐户 flasher 中表 tb1 与表 tb2 存在外键关系,表 tb1 的 deptno 参照了表 tb2 中的 deptno 列
帐户 flasher 中表 tb1 与 scott . emp 具有相同的表结构,表 tb2 与表 scott . dept 具有相同的表结构
下面为表 tb2 新增一个 deptno ,且为表 tb1 新增一条记录
create table tb1 -- 基于表 scott.emp 来创建表 tb1
enable row movement
as select * from scott . emp ;
create table tb2 -- 基于表 scott.dept 来创建表 tb2
enable row movement
as select * from scott . dept ;
alter table tb1 -- 为表 tb1 添加主键约束
add constraint tb1_empno_pk primary key ( empno );
alter table tb2 -- 为表 tb2 添加主键约束
add constraint tb2_deptno_pk primary key ( deptno );
alter table tb1 -- 为表 tb1 添加外键约束
add constraint tb1_tb2_deptno_fk foreign key ( deptno )
references tb2 ( deptno );
insert into tb2 -- 为表 tb2 插入一个新部门
select 50 , 'Customer' , 'Landon' from dual ;
insert into tb1 ( empno , ename , job , deptno ) -- 为表 tb1 插入一个新的雇员
select 8000 , 'Robinson' , 'Clerk' , 50 from dual ;
commit ;
select current_scn from v$database ; -- 获得当前的 scn
--- 687444
delete from tb1 where empno = 8000 ; -- 删除先前新增的部门
delete from tb2 where deptno = 50 ; -- 删除先前新增的雇员
commit ;
flashback table tb1 to scn 687444 ; -- 闪回先前删除的雇员
/*
ERROR at line 1:
ORA-02091: transaction rolled back -- 提示事务被回滚,外键没有找到
ORA-02291: integrity constraint (FLASHER.TB1_TB2_DEPTNO_FK) violated - parent key not found */
flashback table tb1 , tb2 to scn 687444 ; -- 将两个表同时闪回
select empno , ename , deptno , dname -- 此时新增的雇员被闪回,部门也被闪回
from tb1
inner join tb2
using ( deptno )
where deptno = 50 ;
EMPNO ENAME DEPTNO DNAME
---------- ---------- ---------- --------------
8000 Robinson 50 Customer
6. 表闪回的几个常见问题
a. 当闪回删除操作之前,如果某个键值如主键被重用,将导致违反主键约束,闪回失败。
b. 若闪回所需要的 UNDO 信息不存在,将引发 ORA-08180 : no snapshot found based on specified time( 未找到基于指定时间的快照 ) 错误
c. 如果受闪回影响的记录被其它用户锁定,将引发 ORA-00054 : resource busy and acquire with NOWAIT specified ( 资源忙碌 ) 错误
d. 表定义在闪回期间不能发生变化,否则导致 ORA-01466 : unable to read data - table definition has changed( 表定义已变化 ) 错误
e. 闪回前未启用 row movement ,将收到 ORA-08189: cannot flashback the table because row movement is not enabled 错误
f. 对于存在参照关系的情况,建议将主表等一起实施闪回,否则,将收到 ORA-02091: transaction rolled back , ORA-02291 错误
g . SYS 模式中的表不能使用表闪回技术
7. 有关 ORA - 01466 的问题可以参考这里: Flashback 与ORA-01466
三、更多参考
有关闪回特性请参考
Oracle 闪回特性(FLASHBACK DATABASE)
Oracle 闪回特性(FLASHBACK DROP & RECYCLEBIN)
有关基于用户管理的备份和备份恢复的概念请参考:
Oracle 基于用户管理恢复的处理 ( 详细描述了介质恢复及其处理 )
有关 RMAN 的恢复与管理请参考:
有关 Oracle 体系结构请参考:
Oracle 实例和Oracle 数据库(Oracle 体系结构)
Oracle 联机重做日志文件(ONLINE LOG FILE)