暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

Oracle的flashback drop功能

原创 eygle 2019-11-28
623

在生产环境中,可能用户会因为误操作而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 ,PURGE TABLESPACE USER 命令来选择清除回收站。

另外需要注意的是,当我们使用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特性在误操作发生时,给了我们多一个选择,然而更为根本的是,不要让这样的误操作发生。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论