在生产环境中,可能用户会因为误操作而Drop掉了有用的数据表,从而导致了严重的数据库故障,在以前的版本中,恢复这样的错误一般需要通过备份进行不完全恢复,为了加快这类用户错误的恢复过程,Oracle10g提供了flashback drop的功能。
Oracle 10g的flashback drop功能,允许你从当前数据库中恢复一个被drop了的对象,在执行drop操作时,现在Oracle不是真正删除它,而是将该对象自动将放入回收站(RecycleBin),对于一个对象的删除,Oracle其实仅仅就是进行了类似重令名操作。
所谓的回收站,是一个虚拟的容器,用于存放所有被删除的对象。在回收站中,被删除的对象将占用创建时的同样的空间,你甚至还可以对已经删除的表查询,也可以利用flashback功能来恢复它, 这个就是flashback drop功能。
回收站内的相关信息可以从recyclebin/user_recyclebin/dba_recyclebin等视图中获取,或者通过SQL*Plus的show recyclebin 命令查看。
我们简单测试一下这个功能:
SYS AS SYSDBA >connect eygle/eygle
Connected.
EYGLE >create table t1 as select * from dba_users;
Table created.
EYGLE >drop table t1;
Table dropped.
现在Drop掉的表被移入回收站(Recyclebin)中:
EYGLE >show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
---------------- ------------------------------ ------------ -------------------
T1 BIN$83T2+h92CJvgNAgAIMR+0Q==$0 TABLE 2005-03-29:21:52:00
闪回DROP掉的对象,可以使用如下语法命令:
FLASHBACK TABLE <table_name>
TO BEFORE DROP [RENAME TO new_table_name];
恢复时可以给予表不同的名字。
恢复例子中删除的这个对象,只需要使用如下命令即可:
EYGLE > FLASHBACK TABLE t1 TO BEFORE DROP;
Flashback complete.
如果想要彻底清除这些对象,可以使用Purge命令,如:
EYGLE >show recyclebin;
ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
---------------- ------------------------------ ------------ -------------------
T BIN$29ycNBfhan/gNAgAIMR+0Q==$0 TABLE 2004-06-02:15:26:35
EYGLE >purge table t;
Table purged.
EYGLE >show recyclebin;
使用 purge recyclebin可以清除回收站中的所有对象;类似的我们可以通过purge user_recyclebin或者是purge dba_recyclebin来清除不同的回收站对象;通过PURGE TABLESPACE
另外需要注意的是,当我们使用DROP TABLESPACE … INCLUDING CONTENTS命令来删除表空间,表空间中的所有对象会被清除,包括回收站中的内容;当使用DROP USER … CASCADE命令来删除用户时,该用户下所有的对象会被清除,包括回收站中的内容。
当我们想要彻底删除一个表,不想放到回收站中,可以在drop语句中增加purge选项,如:
drop table tablename purge
需要注意的是sysdba的Drop操作不会被记录,Oracle也从不推荐用户使用sysdba身份创建用户对象。
如果我们不希望使用Oracle的recyclebin,可以通过参数禁用这个特性。
在Oracle10gR1中,通过修改一个隐含参数:_recyclebin 为False可以禁用这个特性,在Oracle10gR2中,recyclebin变成了一个常规参数,可以在session/system级动态修改:
SQL> show parameter recyclebin
NAME TYPE VALUE
------------------------------------ ----------- --------------
recyclebin string on
SQL> alter session set recyclebin=off;
会话已更改。
SQL> alter session set recyclebin=on;
会话已更改。
SQL> alter system set recyclebin=off;
系统已更改。
SQL> alter system set recyclebin=on;
系统已更改。
Flashback drop功能使得对于误DROP操作的恢复变得轻而易举。
但是由于Flashback drop功能的引入,一度引起很多用户的困惑,在dba_objects等视图中用户经常会看到一系列的闪回对象(名称以BIN$开头),用户担心空间得不到回收。我们一起来看一下以下一个案例。
在一个生产数据库上,日常的大空间使用对象监控得到如下输出:
SQL> select owner,segment_name,segment_type,tablespace_name,bytes/1024/1024
2 from dba_segments where bytes/1024/1024 > 3072 order by 5 desc
3 /
OWNER SEGMENT_NAME SEGMENT_TYPE TABLESPACE BYTES/1024/1024
---------- ------------------------------ ------------- ---------- ---------------
BOSSMGR BIN$KkmpRTSRNMngRAADuow9AA==$0 TABLE BOSSMGR 7435
BOSSMGR BIN$KkmpRTScNMngRAADuow9AA==$0 TABLE BOSSMGR 6530
BOSSMGR SMS_ORG_9966_MO_2006 TABLE BOSSMGR 4715
BOSSMGR SMS_LOG_9966_MTREP_0605 TABLE BOSSMGR 3895
BOSSMGR SMS_LOG_9966_MTREP_0606 TABLE BOSSMGR 3795
BOSSMGR SMS_ORG_9966_MT TABLE BOSSMGR 3445
BOSSMGR BIN$LUIG2kvKOzDgRAADuow9AA==$0 TABLE BOSSMGR 3360
BOSSMGR SMS_ORG_OPER_MOMT_0606 TABLE BOSSMGR 3335
8 rows selected.
我们注意到在使用空间最多的8个对象中,存在三个闪回对象,占用空间将近17G。
继续检查一下Recyclebin中的Top 10空间使用对象:
SQL> SELECT *
2 FROM (SELECT a.owner, a.object_name, a.original_name,b.segment_type,
3 b.BYTES / 1024 / 1024 mb
4 FROM dba_recyclebin a, dba_segments b
5 WHERE a.object_name = b.segment_name
6 ORDER BY mb DESC)
7 WHERE ROWNUM < 11;
OWNER OBJECT_NAME ORIGINAL_NAME SEGME MB
------- ------------------------------ -------------------------------- ----- -----
BOSSMGR BIN$KkmpRTSRNMngRAADuow9AA==$0 SMS_ORG_OPER_MOMT_0604 TABLE 7435
BOSSMGR BIN$KkmpRTScNMngRAADuow9AA==$0 SMS_ORG_OPER_MOMT_0605 TABLE 6530
BOSSMGR BIN$LUIG2kvKOzDgRAADuow9AA==$0 SMS_LOG_9966_MTREP_BACK TABLE 3360
BOSSMGR BIN$KkmpRTSoNMngRAADuow9AA==$0 SMS_ORG_OPER_RESPONSE_0605 TABLE 2740
BOSSMGR BIN$LUIG2kvTOzDgRAADuow9AA==$0 SMS_ORG_HS_MTREP_BACK TABLE 2685
BOSSMGR BIN$KkmpRTShNMngRAADuow9AA==$0 SMS_ORG_OPER_RESPONSE_0604 TABLE 2375
BOSSMGR BIN$KzwoB69KbnzgRAADuow9AA==$0 SMS_ORG_9966_MO_2007 TABLE 1735
BOSSMGR BIN$KkmpRTSbNMngRAADuow9AA==$0 PK2_SMS_ORG_OPER_MOMT INDEX 1715
BOSSMGR BIN$LUGjxqpdLe7gRAADuow9AA==$0 SMS_LOG_MO_BACK TABLE 1645
BOSSMGR BIN$KkmpRTSnNMngRAADuow9AA==$0 PK_SMS_ORG_OPER_RESPONSE INDEX 1455
10 rows selected.
如果进一步统计一下,发现这些闪回对象占用的空间达到了40多个G:
SQL> select sum(bytes)/1024/1024/1024 from dba_segments where segment_name like 'BIN$%';
SUM(BYTES)/1024/1024/1024
-------------------------
44.7367554
那么我们可以尝试手工释放一下这些空间,首先我们可以记录一下当前的表空间剩余空间:
SQL> SELECT tablespace_name, SUM (BYTES) / 1024 / 1024 "Free_MB"
2 FROM dba_free_space
3 GROUP BY tablespace_name ORDER BY 2;
TABLESPACE Free_MB
---------- ----------
DBMON 8.5
USERS 93.6875
SYSAUX 154.8125
SYSTEM 161.0625
UNDOTBS1 5888.5
BOSSMGR 48835
从DBA_FREE_SPACE视图我们可以获得当前表空间的剩余空间,其中BOSSMGR还剩余约48G空间。
接下来尝试清除一个闪回对象:
SQL> purge table bossmgr.SMS_ORG_OPER_MOMT_0604;
Table purged.
清除之后可以发现,闪回对象的空间占用缩减了,但是数据库显示的自由空间却并未增加:
SQL> SELECT SUM (BYTES) / 1024 / 1024 / 1024 "Flash Objects" FROM dba_segments
2 WHERE segment_name LIKE 'BIN$%';
Flash Objects
-------------
37.4760132
SQL> SELECT tablespace_name, SUM (BYTES) / 1024 / 1024 "Free_MB"
2 FROM dba_free_space
3 GROUP BY tablespace_name ORDER BY 2;
TABLESPACE Free_MB
---------- ----------
DBMON 8.5
USERS 93.6875
SYSAUX 154.8125
SYSTEM 161.0625
UNDOTBS1 5888.5
BOSSMGR 48835
那么是哪里发生了变化呢?
变化发生在dba_free_space视图的构成上,在Oracle 10g中,如果启用flash drop功能,在drop表时,数据库不会直接删除,而是将其放在回收站中,当空间出现短缺时,这个空间才会逐渐被回收;但是当对象删除之后,这部分空间会记入free space,也就是说被包含在dba_free_space的查询结果之中,这部分空间可以被看作是自由空间,可以被使用的。
来看一下Oracle 10g中这个视图的构成:
SQL> SET long 9999
SQL> SET pagesize 99
SQL> SELECT text FROM dba_views
2 WHERE view_name = 'DBA_FREE_SPACE';
TEXT
--------------------------------------------------------------------------------
select ts.name, fi.file#, f.block#,
f.length * ts.blocksize, f.length, f.file#
from sys.ts$ ts, sys.fet$ f, sys.file$ fi
where ts.ts# = f.ts#
and f.ts# = fi.ts#
and f.file# = fi.relfile#
and ts.bitmapped = 0
union all
select /*+ ordered use_nl(f) use_nl(fi) */
ts.name, fi.file#, f.ktfbfebno,
f.ktfbfeblks * ts.blocksize, f.ktfbfeblks, f.ktfbfefno
from sys.ts$ ts, sys.x$ktfbfe f, sys.file$ fi
where ts.ts# = f.ktfbfetsn
and f.ktfbfetsn = fi.ts#
and f.ktfbfefno = fi.relfile#
and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
union all
select /*+ ordered use_nl(u) use_nl(fi) */
ts.name, fi.file#, u.ktfbuebno,
u.ktfbueblks * ts.blocksize, u.ktfbueblks, u.ktfbuefno
from sys.recyclebin$ rb, sys.ts$ ts, sys.x$ktfbue u, sys.file$ fi
where ts.ts# = rb.ts#
and rb.ts# = fi.ts#
and rb.file# = fi.relfile#
and u.ktfbuesegtsn = rb.ts#
and u.ktfbuesegfno = rb.file#
and u.ktfbuesegbno = rb.block#
and ts.bitmapped <> 0 and ts.online$ in (1,4) and ts.contents$ = 0
union all
select ts.name, fi.file#, u.block#,
u.length * ts.blocksize, u.length, u.file#
from sys.ts$ ts, sys.uet$ u, sys.file$ fi, sys.recyclebin$ rb
where ts.ts# = u.ts#
and u.ts# = fi.ts#
and u.segfile# = fi.relfile#
and u.ts# = rb.ts#
and u.segfile# = rb.file#
and u.segblock# = rb.block#
and ts.bitmapped = 0
注意以上视图的创建语句中,第一个Union ALL结合起来的结果和Oracle 9i之中的一致,而后两个Union ALL结合的部分则包括了recyclebin$中对象占用的空间,也就是说在Oracle 10g中Oracle将闪回对象的空间记入了自由空间。这一改变在Oracle 10g中可能带来额外的影响,如果回收站中的对象很多,那么查询dba_free_space视图可能变得很慢,这一点大家需要注意。
可以通过测试数据库对Oracle的自动空间回收进行一点研究,以发现Oracle是如何自动回收闪回对象的空间的。
首先限定一下数据文件的大小,并指定测试用户使用该数据文件表空间:
SQL> alter database datafile '/data2/ora10g/oradata/mars/eygle01.dbf' resize 20M;
Database altered.
SQL> alter user eygle default tablespace eygle;
User altered.
SQL> connect eygle/eygle
Connected.
SQL> select tablespace_name,bytes/1024/1024 from dba_data_files
2 where tablespace_name='EYGLE';
TABLESPACE_NAME BYTES/1024/1024
------------------------------ ---------------
EYGLE 20
在回收站创造一个闪回对象,占用一定空间:
SQL> select segment_name,bytes/1024/1024 from user_segments;
SEGMENT_NAME BYTES/1024/1024
------------------------------ ---------------
BIN$LoYA94V+Mg3gRAADumixHQ==$0 12.25
创建一个新的测试表用于插入:
SQL> create table eygle3 as select * from dba_objects where 1=0;
Table created.
设置10046事件跟踪插入过程:
SQL> alter session set events='10046 trace name context forever,level 12';
Session altered.
SQL> begin
2 for i in 1 .. 10 loop
3 insert into eygle3 select * from dba_objects;
4 commit;
5 end loop;
6 end;
7 /
PL/SQL procedure successfully completed.
这个插入完成之后,可以发现,由于表空间的剩余空间不够使用,Oracle清除了闪回对象,新的对象使用了12.25MB空间:
SQL> select segment_name,bytes/1024/1024 from user_segments;
SEGMENT_NAME BYTES/1024/1024
------------------------------ ---------------
EYGLE3 12.25
可以检查一下跟踪文件,使用tkprof格式化,使之便于阅读,其中有这样的主要操作:
select obj#, type#, flags, related, bo, purgeobj, con#
from RecycleBin$ where ts#=:1 and to_number(bitand(flags, 16)) = 16
order by dropscn
drop table "EYGLE"."BIN$LoYA94V+Mg3gRAADumixHQ==$0" purge
前一个用于按照dropscn的升序顺序查找闪回对象,后面语句则用于删除这些对象释放空间。可以知道,如果在DML操作中,动态由数据库来释放空间将会带来额外的消耗,特别是大的空间对象,所以,如果能够确认删除对象,则可以使用purge命令完全删除,这样可以减少动态空间回收带来的性能影响:
SQL> drop table eygle3 purge;
Table dropped.
SQL> select * from tab;
no rows selected
需要注意的是,Flashback Drop特性对于一些依赖对象的处理,如triggers, constraints, and indexes 等,这些对象被同时恢复,但是名称却和回收站中的相同,不会变更回原名称,需要手工更改回期望的名称,以下测试展示了主键索引在闪回前后的变化:
SQL> select * from v$version where rownum <2;
BANNER
-----------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
SQL> create table eygle (id number primary key,name varchar2(20));
Table created.
SQL> desc eygle;
Name Null? Type
----------------------------------------- -------- ----------------
ID NOT NULL NUMBER
NAME VARCHAR2(20)
SQL> select index_name from user_indexes where table_name='EYGLE';
INDEX_NAME
------------------------------
SYS_C0016881
SQL> drop table eygle;
Table dropped.
此时回收站中存在了表和索引两个对象:
SQL> select object_name,original_name,type,createtime from recyclebin;
OBJECT_NAME ORIGINAL_NAME TYPE CREATETIME
------------------------------ ----------------- ---------- -------------------
BIN$03fpw5bNQsGjxcj4bysM1A==$0 SYS_C0016881 INDEX 2010-12-19:21:53:32
BIN$5c8c1duSSviKl8aZso9ICQ==$0 EYGLE TABLE 2010-12-19:21:53:32
执行闪回操作:
SQL> flashback table EYGLE to before drop;
Flashback complete.
SQL> select object_name,original_name,type,createtime from recyclebin;
no rows selected
注意此时的主键索引仍然维持了回收站中的名字:
SQL> select index_name from user_indexes where table_name='EYGLE';
INDEX_NAME
------------------------------
BIN$03fpw5bNQsGjxcj4bysM1A==$0
除此之外,在执行闪回时还有以下注意事项需要知悉:
1.某些约束,如外键,不能被闪回,将会丢失
2.Bitmap Join Indexes无法闪回
3.Materialized view logs不会被存放在回收站中,其内容会丢失
4.在闪回表时,可能表的部分索引会丢失,这和order by dropscn的空间事务处理有关
Flashback Drop特性在误操作发生时,给了我们多一个选择,然而更为根本的是,不要让这样的误操作发生。