闪回(Flashback)
SQL> /*
SQL> 错误操作:
SQL> 1. 错误的delete一条记录,并且commit
SQL> 2. 错误地删除了一个表: drop table
SQL> 3. 查询某个表的历史记录(所有已经提交了的历史记录)
SQL> 4. 错误地执行了一个事务
SQL>
SQL> 对应闪回的四种类型:
SQL> 1. 闪回表
SQL> 2. 闪回删除
SQL> 3. 闪回版本查询
SQL> 4. 闪回事务查询
SQL> 5. 闪回 数据库
SQL> */
SQL> host cls
SQL> --闪回的时间参数
SQL> conn / as sysdba
已连接。
SQL> show user
USER 为 "SYS"
SQL> show parameters undo;
l闪回表,实际上是将表中的数据快速恢复到过去的一个是焦点或者系统改变号SCN上。实现表的闪回,需要使用到与撤销表空间相关的undo信息,通过show parameter undo命令可以了解这些信息。
l
l用户对表数据的修改操作,都记录在撤销表空间中,这为表的闪回提供了数据恢复的基础。例如,某个修改操作在提交后被记录在撤销表空间中,保留时间为900秒,用户可以在这900秒的时间内对表进行闪回操作,从而将表中的数据恢复到修改之前的状态。
NAME TYPE VALUE
undo_management string AUTO
undo_retention integer 900
undo_tablespace string UNDOTBS1
SQL> -- 将900秒改为20分钟
SQL> alter system set undo_retention=1200 scope=both;
系统已更改。
SQL> show parameters undo;
NAME TYPE VALUE
undo_management string AUTO
undo_retention integer 1200
undo_tablespace string UNDOTBS1
SQL> /*
SQL> scope的取值: session spfile(参数文件) both
SQL> */
SQL> --为scott授予闪回的权限
SQL> grant flashback any table to scott;
授权成功。
SQL> conn scott/tiger
已连接。
SQL> show user
USER 为 "SCOTT"
SQL> host cls
SQL> --第一种类型闪回:闪回表
SQL> create table flashback_table1
2 (fid number,fnamevarchar2(10));
表已创建。
SQL> insert into flashback_table1 values(&fid,'&fname');
输入 fid 的值: 1
输入 fname 的值: Tom
SQL> commit;
提交完成。
SQL> select * from flashback_table1;
FID FNAME
1 Tom
2 Mary
3 Mike
SQL> --记录当前的系统时间(SCN)
SQL> select sysdate 时间, timestamp_to_scn(sysdate) SCN fromdual;
时间 SCN
21-9月 -11 4354761
SQL> delete from flashback_table1 wherefid=2;
已删除 1 行。
SQL> commit;
提交完成。
SQL> select * from flashback_table1;
FID FNAME
---------- ----------
1 Tom
3 Mike
SQL> --执行闪回表
SQL> flashback table flashback_table1 toscn 4354761;
flashback table flashback_table1 to scn4354761
*
第 1 行出现错误:
ORA-08189: 因为未启用行移动功能, 不能闪回表
SQL> select rowid,fid,fname fromflashback_table1;
ROWID FID FNAME
------------------ ---------- ----------
AAANh7AAEAAAAGnAAA 1 Tom
AAANh7AAEAAAAGnAAC 3 Mike
SQL> --开启行移动功能
SQL> alter table flashback_table1 enable row movement;
表已更改。
SQL> flashback table flashback_table1 to scn 4354761;
闪回完成。
SQL> select rowid,fid,fname fromflashback_table1;
ROWID FID FNAME
------------------ --------------------
AAANh7AAEAAAAGnAAB 1 Tom
AAANh7AAEAAAAGnAAD 2 Mary
AAANh7AAEAAAAGnAAE 3 Mike
闪回表语法:
FLASHBACK TABLE [schema.]
TO
{[BEFORE DROP [RENAME TO table]]
[SCN|TIMESTAMP]expr
[ENABLE|DISABLE]TRIGGERS}
lschema:模式名,一般为用户名。
lTO TIMESTAMP:系统邮戳,包含年、月、日、时、分、秒。
lTO SCN:系统更改号,
lENABLE TRIGGERS:表示触发器恢复以后为enable状态,而默认为disable状态。
lTO BEFORE DROP:表示恢复到删除之前。
lRENAME TO table:表示更换表名。
SQL> --闪回表的思想:将表回退到过去的一个时间上
SQL> --问题:不知道过去时间,怎么办?
SQL> host cls
SQL> --闪回删除
SQL> -- Oracle的回收站
SQL> select * from tab;
TNAME TABTYPE CLUSTERID
------------------------------ -----------------
DEPT TABLE
EMP TABLE
BONUS TABLE
SALGRADE TABLE
FLASHBACK_TABLE TABLE
FLASHBACK_TABLE1 TABLE
SYS_TEMP_FBT TABLE
已选择7行。
删除表。
drop table FLASHBACK_TABLE;
查看回收站
show recyclebin;
清空回收站
purge recyclebin;
彻底删除
drop table FLASHBACK_TABLE1 purge;
回收站只对普通用户有效
删除表
drop table test123;
show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
TEST123 BIN$w6NYaQ1jSZ6uzO2jUQ/ALw==$0 TABLE 2011-09-21:10:35:32
SQL> --闪回删除:从回收站中取回表
SQL> flashback table test123 to before drop;
闪回完成。
SQL> --通过回收站中的名称闪回删除
SQL> flashback table"BIN$9JMrb6kbRCON287lDV+5dA==$0" to before drop;
闪回完成。
SQL> host cls
闪回删除:回收站(recyclebin)简介
l回收站是所有被删除对象及其相依对象的逻辑存储容器,例如当一个表被删除(drop)时,该表及其相依对象并不会马上被数据库彻底删除,而是被保存到回收站中。
l
l回收站将用户执行的drop操作记录在一个系统表中,也就是将被删除的对象写到一个数据字典中。如果确定不再需要该对象,可以使用purge命令对回收站进行清空。
l
l被删除的对象的名字可能是相同的,例如用户创建了一个test表,使用drop命令删除该表后,又创建了一个test表,这时,如果再次删除该表就会导致向回收站中添加了两个相同的表。
l
回收站中对象的命名规则
l为了确保添加到回收站中的对象的名称都是唯一的,系统会对这些保存到回收站中的对象进行重命名,重命名的格式如下:
l
BIN$globalUID$version
l
•其中: BIN表示RECYCLEBIN;globalUID是一个全局唯一的、24个字节长的对象,该标识与原对象名没有任何关系;version指数据库分配的版本号。
SQL> -- 闪回重名的表
SQL> select * from tab;
TNAME TABTYPE CLUSTERID
------------------------------ -----------------
DEPT TABLE
EMP TABLE
BONUS TABLE
SALGRADE TABLE
TEST123 TABLE
SYS_TEMP_FBT TABLE
已选择6行。
SQL> drop table TEST123;
表已删除。
SQL> select * from tab;
TNAME TABTYPE CLUSTERID
------------------------------ -----------------
DEPT TABLE
EMP TABLE
BONUS TABLE
SALGRADE TABLE
BIN$eqIO0J1LQ0G1rYAnIHWrdg==$0 TABLE
SYS_TEMP_FBT TABLE
已选择6行。
SQL> create table test123(tid number);
表已创建。
SQL> insert into test123 values(1);
已创建 1 行。
SQL> insert into test123 values(2);
已创建 1 行。
SQL> commit;
提交完成。
SQL> drop table test123;
表已删除。
SQL> --查询回收站:应该有两个重名的test123
SQL> show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
---------------------------------------------- ------------
TEST123 BIN$HDhYGEaXTayAnETFAUoaNw==$0 TABLE 2011-09-21:10:41:59
TEST123 BIN$eqIO0J1LQ0G1rYAnIHWrdg==$0 TABLE 2011-09-21:10:41:17
SQL> --闪回这两个表
SQL> flashback table test123 to beforedrop;
闪回完成。
SQL> show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
---------------------------------------------- ------------
TEST123 BIN$eqIO0J1LQ0G1rYAnIHWrdg==$0 TABLE 2011-09-21:10:41:17
SQL> --闪回同名的表,先闪回最后删除那个
SQL> select * from tab;
TNAME TABTYPE CLUSTERID
------------------------------ -----------------
DEPT TABLE
EMP TABLE
BONUS TABLE
SALGRADE TABLE
BIN$eqIO0J1LQ0G1rYAnIHWrdg==$0 TABLE
SYS_TEMP_FBT TABLE
TEST123 TABLE
已选择7行。
SQL> flashback table test123 to beforedrop;
flashback table test123 to before drop
*
第 1 行出现错误:
ORA-38312: 原始名称已被现有对象使用
SQL> --重命名
SQL> flashback table test123 to beforedrop rename to test1234;
闪回完成。
SQL> select * from tab;
TNAME TABTYPE CLUSTERID
------------------------------ -----------------
DEPT TABLE
EMP TABLE
BONUS TABLE
SALGRADE TABLE
TEST1234 TABLE
SYS_TEMP_FBT TABLE
TEST123 TABLE
已选择7行。
SQL> select * from test123;
TID
----------
1
2
SQL> select * from test1234;
TID TNAME
---------- --------------------
1 Tom
SQL> host cls
闪回 删除: 需要考虑的事情
l闪回删除对下列表无效:
在SYSTEM 表空间内的表
用精细审计的数据库或 虚拟的私人数据库
属于字典管理的表空间
由于空间不足已经被手动或自动删除的表
l以下依赖不被保护:
位图索引
表之前删掉的索引
lFLASHBACK TABLE命令作为单一的事务执行,会得到一个单一的DML锁
表的统计数据不会被闪回
当前的索引和从属的对象会被维持
l闪回表操作:
系统表不能被闪回
不能跨越DDL操作
会被写入警告日志
产生撤销和重做的数据
SQL> --闪回版本查询
SQL> creat table versions_table
SP2-0734: 未知的命令开头 "creat tabl..."- 忽略了剩余的行。
SQL> create table versions_table
2 (vid number,
3 vname varchar(20));
表已创建。
SQL> insert into versions_tablevalues(1,'Tom');
已创建 1 行。
SQL> commit;
提交完成。
SQL> insert into versions_tablevalues(2,'Mary');
已创建 1 行。
SQL> commit;
提交完成。
SQL> insert into versions_tablevalues(3,'Mike');
已创建 1 行。
SQL> commit;
提交完成。
SQL> update versions_table setvname='Mary123' where vid=2;
已更新 1 行。
SQL> commit;
提交完成。
SQL> select * from versions_table;
VID VNAME
1 Tom
2 Mary123
3 Mike
SQL> /*
SQL> 问题:1
SQL> 1. 如何获取前面三个版本?
SQL> 2. 如何获取该表过去的一个时间?
SQL> */
闪回版本查询
闪回版本查询,提供了一个审计行改变的查询功能,通过它可以查找到所有已经提交了的行记录。其语法格式如下:
selectcolumn_name[,column_name,...]
from table_name
versionsbetween [SCN|TIMESTAMP] [expr|MINVALUE]
and [epxr|MAXVALUE] as of [SCN|TIMESTAMP]expr;
备注:
其中:column_name列名;table_name表名;between...and时间段;SCN系统改变号;TIMESTAMP时间戳;ASOF表示恢复单个版本;MAXVALUE最大值;MINVALUE最小值;expr指定一个值或者表达式。
SQL> --执行闪回版本查询,获取所有的版本信息
SQL> selectvid,vname,versions_operation,versions_starttime,versions_endtime
2 from versions_table
3 versions between timestampminvalue and maxvalue
4 order by 1,4;
SQL> col VERSIONS_STARTTIME for a20
SQL> col VERSIONS_ENDTIME for a20
SQL> /
SQL> col vname for a8
SQL> /
SQL> col VERSIONS_STARTTIME for a30
SQL> col VERSIONS_ENDTIME for a30
SQL> /
SQL> set linesize 150
SQL> /
VID VNAME VVERSIONS_STARTTIME VERSIONS_ENDTIME
---------- -------- - ------------------------------
1Tom I 21-9月 -11 11.01.09 上午
2Mary I 21-9月 -11 11.01.24 上午 21-9月 -11 11.02.00 上午
2Mary123 U 21-9月 -11 11.02.00 上午
3Mike I 21-9月 -11 11.01.39 上午
SQL> /*
SQL> selectvid,vname,versions_operation,versions_starttime,versions_endtime
SQL> from versions_table
SQL> versions between timestamp minvalueand maxvalue
SQL> order by 1,4;
SQL> */
SQL> --通过闪回版本查询,可以获取某个表过去已经提交了的历史版本信息
SQL> --通过闪回版本查询,可以获取某个表过去已经提交了的历史版本信息
SQL> host cls
SQL> --闪回事务查询
SQL> create table transaction_table
2 (tid number,tnamevarchar(20));
表已创建。
SQL> --第一个事务
SQL> insert into transaction_tablevalues(1,'Tom');
已创建 1 行。
SQL> insert into transaction_table values(2,'Mary');
已创建 1 行。
SQL> insert into transaction_tablevalues(3,'Mike');
已创建 1 行。
SQL> commit;
提交完成。
SQL> --第二个事务
SQL> update transaction_table settname='Mary123' where tid=2;
已更新 1 行。
SQL> delete from transaction_table wheretid=3;
已删除 1 行。
SQL> commit;
提交完成。
l闪回事务查询实际上闪回版本查询的一个扩充,通过它可以审计某个事务甚至撤销一个已经提交的事务。
l实现闪回事务查询,需要先了解flashback_transaction_query视图,从该视图中可以获取事务的历史操作记录以及撤销语句(UNDO_SQL)。
l使用闪回事务查询,可以了解某个表的历史操作记录,这个操作记录对应一个撤销SQL语句,如果想要撤销这个操作,就可以执行这个SQL语句。
Flashback_transaction_query
名称 类型 说明
------------------------------------------------------------------------------------------------
XID RAW(8) 事务编号
START_SCN NUMBER 事务的开始的系统改变号
START_TIMESTAMP DATE 事务的开始时间
COMMIT_SCN NUMBER 事务提交时的系统改变号
COMMIT_TIMESTAMP DATE 事务提交时的时间
LOGON_USER VARCHAR2(30) 对应的用户
UNDO_CHANGE# NUMBER 撤销操作对应的编号
OPERATION VARCHAR2(32) 操作
TABLE_NAME VARCHAR2(256) 表
TABLE_OWNER VARCHAR2(32) 所有者
ROW_ID VARCHAR2(19) 行号
UNDO_SQL VARCHAR2(4000) 撤销事务的SQL语句
注意,要查询flashback_transaction_query视图的信息,需要有select any transaction的权限。
SQL> --如何撤销第二个事务? ----闪回事务查询
SQL> --授权select any transaction给scott
SQL> conn / as sysdba
已连接。
SQL> grant select any transaction toscott;
授权成功。
SQL> conn scott/tiger
已连接。
SQL> /*
SQL> 闪回事务查询的步骤:1
SQL> 1. 通过闪回版本查询获取事务号(xid)
SQL> 2. 通过xid查询Flashback_transaction_query,获取undo_sql
SQL> */
SQL> select tid,tname,versions_operation,versions_starttime,versions_endtime,versions_xid
2 from transaction_table
3 versions between timestampminvalue and maxvalue
4 order by versions_xid;
TID TNAME V VERSIONS_STARTTIME VERSIONS_ENDTIME VERSIONS_XID
2 Mary123 U 21-9月 -11 11.13.24 上午 0400140020040000
3 Mike D 21-9月 -11 11.13.24 上午 0400140020040000
2 Mary I 21-9月 -11 11.12.39 上午 21-9月 -11 11.13.24 上午 0700250012040000
1 Tom I 21-9月 -11 11.12.39 上午 0700250012040000
3 Mike I 21-9月 -11 11.12.39 上午 21-9月 -11 11.13.24 上午 0700250012040000
SQL> -- 执行闪回事务查询
SQL> select operation,undo_sql
2 fromFlashback_transaction_query
2 fromFlashback_transaction_query
3 where xid='0400140020040000';
OPERATION
--------------------------------
UNDO_SQL
------------------------------------------------------------------------------------------------------------------------------------------------------
DELETE
insert into"SCOTT"."TRANSACTION_TABLE"("TID","TNAME")values ('3','Mike');
UPDATE
update"SCOTT"."TRANSACTION_TABLE" set "TNAME" = 'Mary'where ROWID = 'AAANiBAAEAAAAG3AAB';
BEGIN
SQL> update"SCOTT"."TRANSACTION_TABLE" set "TNAME" = 'Mary'where ROWID = 'AAANiBAAEAAAAG3AAB';
已更新 1 行。
SQL> insert into"SCOTT"."TRANSACTION_TABLE"("TID","TNAME")values ('3','Mike');
已创建 1 行。
SQL> commit;
提交完成。
SQL> select * from TRANSACTION_TABLE;
TID TNAME
---------- --------------------
1 Tom
2 Mary
3 Mike
SQL> host cls
SQL> spool off