Oracle提供了7种闪回技术,分别为:闪回drop、闪回查询、闪回数据归档、闪回表、闪回版本查询、闪回事务、闪回数据库。此次验证下Oracle数据库闪回drop和闪回查询。
一、闪回DROP
又名闪回删除。
1、理解回收站(recyclebin)
从管理的角度为每个用户“分配”一个回收站,但这个回收站并不实际开辟空间(只是个逻辑容器),当drop table时(非purge),原来的表所使用的段中的数据并没有真正的删除。实际上是把table的段名以回收站方式重命名。该段所在表空间不足需要扩展时,回收站中的信息会被自动清除。(先清除后扩展)
示例:
SQL> show parameter recyclebin
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
recyclebin string ON
当初始化参数recyclebin为on时,每个用户都有了自己的回收站(延迟参数,session下次连接有效)
如果参数设为off 就取消了用户的回收站,那么当你drop table就相当于purge了。
SQL> create tablespace test datafile '/u01/oradata/prod/test01.dbf' size 1m;
SQL> create table scott.t1(id int) tablespace test;
SQL> select segment_name from dba_segments where tablespace_name='TEST'; 查看test表空间下有了一个段
SEGMENT_NAME
T1
SQL> select sum(bytes) from dba_free_space where tablespace_name='TEST'; 看这个段有多少空闲空间
SUM(BYTES)
----------
917504
SQL> insert into scott.t1 values(1);
SQL> insert into scott.t1 select * from scott.t1; 将表空间撑满
/
/
第 1 行出现错误:
ORA-01653: 表 SCOTT.T1 无法通过string (在表空间 TEST 中) 扩展
SQL> select count(*) from scott.t1;
COUNT(*)
----------
65536
SQL> select sum(bytes) from dba_free_space where tablespace_name='TEST'; 没有空闲空间
SQL> drop table scott.t1;
SQL> select segment_name from dba_segments where tablespace_name='TEST';
SEGMENT_NAME
---------------------------------------------------------------------------------
BIN$4KZBTYTKocDgQAB/AQAKRA==$0
SQL> select sum(bytes) from dba_free_space where tablespace_name='TEST';
SUM(BYTES)
----------
983040
请看,TEST表空间中的空闲空间又回来了,这说明如果test表空间不够时,这部分空闲空间是可以被重新利用的,实际上即使你设置了表空间autoextend特性,Oracle 会先使用recyclebin,若空间还不够,再考虑autoextend.
SQL> create table scott.emp1 tablespace test as select * from scott.emp; 挤占test表空间
SQL> select sum(bytes) from dba_free_space where tablespace_name='TEST';
SUM(BYTES)
----------
917504
SQL> select segment_name from dba_segments where tablespace_name='TEST';
SEGMENT_NAME
---------------------------------------------------------------------------------
EMP1
t1表的数据已经被冲掉了,使用闪回删除无法找回了。
2、关于回收站中的对象的闪回和清除
闪回和清除的顺序不同
闪回使用LIFO (后进先出)
清除使用FIFO (先进先出)
假设回收站里有两个t1表,看以下两条语句:
SQL> flashback table t1 to before drop; 闪回的是最新的那个t1表。
SQL> purge table t1; 清除的是最旧的那个t1表。
如果想避免混淆,可以直接给出回收站里的表名
SQL> flashback table " BIN$qrJLbL74ZgvgQKjA8Agb/A==$0" to befroe drop; (注意双引号)
SQL> purge table "BIN$qrJLbL74ZgvgQKjA8Agb/A==$0";
SQL> purge recyclebin; 清空回收站
3、如何恢复同一个schema下准备闪回的表已有同名的对象存在,闪回drop需要重命名.
SQL> flashback table t1 to before drop rename to test_old;
4、system 表空间的对象没有回收站,所以在sys下缺省使用system表空间时,drop table会直接删除对象
5、如果一个表上面有索引和约束,drop后再闪回表,索引和约束还在吗?
create table t (id int,name char(10));
alter table t add constraint pk_t primary key(id);
insert into t values (1,'test1');
insert into t values (2,'test2');
commit;
SQL> select * from t;
ID NAME
---------- ----------
1 test1
2 test2
看一眼约束和索引
SQL> select * from user_indexes;
SQL> select * from user_constraints;
SQL> drop table t; 表被drop到回收站,再看一眼约束和索引
SQL> select * from user_indexes; 索引不见了
SQL> select * from user_constraints; 约束有,但乱码(除外键约束外)
SQL> flashback table t to before drop;
再看约束和索引
SQL> select * from user_indexes; 索引回来了,但乱码
SQL> select * from user_constraints; 约束也在,但乱码
分别重命名索引和约束
SQL> alter index "BIN$yF3hbvIbioTgQAB/AQAJlg==$0" rename to pk_t;
SQL> alter table t rename constraint "BIN$yF3hbvIaioTgQAB/AQAJlg==$0" to pk_t;
6、查看闪回区内容
select OBJECT_NAME,ORIGINAL_NAME,OPERATION,CREATETIME,DROPTIME from user_recyclebin;
select * from tab;
二、闪回查询
flashback query:(用于DML 误操作并且commit)
1、要点:
利用在undo tablespace 里已经提交的undo block(未被覆盖),可以查询表的过去某个时间点的数据。
通过设置undo_retention参数设置前镜像的保留时间。
查询的语法:
select … as of scn | timestamp
2、undo_retention
可以通过show parameter undo_retention查看该参数的值,默认900,单位是秒。关于undo_retention的介绍可以查看lian链接:link
3、示例:
sys:
create table scott.student (sno int,sname char(10),sage int);
insert into scott.student values(1,'tt1',21);
insert into scott.student values(2,'tt2',22);
insert into scott.student values(3,'tt3',23);
insert into scott.student values(4,'tt4',24);
commit;
SQL> select * from scott.student;
SQL> select current_scn from v$database; 取scn 1或者查询当前时间
SQL> delete scott.student where sno=1;
SQL> commit;
SQL> select * from scott.student;
SQL> select current_scn from v$database; 取scn 2
SQL> update scott.student set sage=50;
SQL> commit;
SQL> select * from scott.student;
SQL>select * from scott.student as of scn scn1; 闪回查询到scn1;
SQL>select * from scott.student as of scn scn2; 闪回查询到scn2;
SQL>select * from scott.student as of timestamp to_timestamp('2019-03-18 11:31:01','YYYY-MM-DD HH24:MI:SS'); //闪回查询基于时间
4、查看 DELETE 及 UPDATE 操作修改的数据:
SQL> SELECT *
FROM tab AS OF TIMESTAMP to_timestamp('time_point', 'yyyy-mm-dd hh24:mi:ss')
MINUS
SELECT *
FROM tab;
其中将查询得 tab 表在 time_point 时点之后因 DELETE 及 UPDATE 操作修改的数据。
5、查看 INSERT 操作修改的数据:
SQL> SELECT *
FROM tab
MINUS
SELECT *
FROM tab AS OF TIMESTAMP to_timestamp('time_point', 'yyyy-mm-dd hh24:mi:ss');
其中将查询得 tab 表在 time_point 时点之后因 INSERT 操作修改的数据。