Oracle Flashback(闪回) 详解

通常我们对数据库进行了误操作时, 需要把数据库Rollback到之前的版本。一个常用的方法就是使用日志来进行数据库恢复. 这个方法虽然强大有效, 但是花费时间等成本高。

例如当我们只是误提交了1个delete语句, 丢失了删除行的数据时, 如果我们执行数据库恢复的话, 就需要断开当前所有server processes, 甚至需要关闭数据库,相当于暂停了所有的生产活动。

而且使用日志恢复的话, 还往往需要相当长的时间(取决于备份文件的复制时间和日志的应用时间)

一, 什么是Flashback

除了上面所说的日志恢复机制.

Oracle提供了另1个快速数据库恢复机制, 就是Flashback. 

1.1 Flashback的简单原理

Oracle会将数据库数据的每1个改动记录在日志文件中, 所以理论上依靠日志文件, 是能将数据库回滚到任何一个时间点的.

而Flashback的机制有点类似与回收站, 会把数据库改动前的镜像放到undo表空间中.

如果用户要rollback1个数据库对象, 只需要找到undo表空间中对应的Undo数据即可.

1.2 Flashback的优点 

很明显, Flashback并不依赖于日志文件, 只需Undo表空间中undo数据即可发挥作用.

所以Flashback可以满足用户逻辑错误的快速恢复.

所以优点如下:

1. 快速

2. 在线恢复, 无需关闭数据库

3. 操作简单.便捷.

1.3 Flashback的缺点

Flashback缺点同样明显.

1. 只适用于用户逻辑错误, 所谓逻辑错误就是用户对数据的唔操作, 例如误删除一些数据行等等.

  而对于数据文件的损坏则无能为力(只能通过日志恢复).

2. undo表空间的容量有限, 旧的undo数据有可能会被新的数据覆盖, 所以Flashback一般只适用于短时间内的恢复, 对于一段相当时间前的误操作, 很可能因为undo数据被覆盖而恢复失败.

1.4 启用Flashback功能

为了正常使用Flashback功能, 通常我们要打开补充日志(Supplemental logging)功能, oracle 11g数据库默认情况下补充日志是关闭的.

补充日志也分成几个级别,最小(Minimal),支持所有字段(all),支持主键(primary key),支持唯一键(unique),支持外键(foreign key)。包括LONG,LOB,LONG RAW及集合等字段类型均无法利用补全日志.

例如:

使用如下命令来打开最小补全日志.

alter database add supplemental log data;

使用如下命令来查看补全日志是否被打开.

SQL> select supplemental_log_data_min, supplemental_log_data_pk, supplemental_log_data_ui, supplemental_log_data_fk, supplemental_log_data_all from v$database;

SUPPLEME SUP SUP SUP SUP
-------- --- --- --- ---
YES  NO  NO  NO  NO

使用Flashback 需要当前用户具有select any transaction 权限.

可以用dba账号执行:

grant select any transaction to xxx;

来获得这个权限.

1.5 关于flashback 的undo设置, Automatic Undo Management

11g我们一般使用Automatic Undo Management(自动撤销管理表空间), 提到这个, 就不得不提到手动管理的回滚段(Rollback segment).
 
在oracle 9i及之前, 回滚段的管理和监控是需要dba手工介入的, 创建合适的回滚段是1件非常耗费dba精力的事情.  dba可能需要不短关注oracle运行情况很长一阵子时间按后, 通过不断尝试调整才能确定一段时间内合适的回滚段大小. 一旦回滚段创建的不合适, 就极有可能引起性能问题甚至error.
 
在9i 之后, oracle 为了清晰整个概念, 取消了回滚段的说法(实际上并未取消回滚段),  而完全用undo来代替, 这也正好与redo相对应.  1个撤销, 1个重做.
 回滚段不再由dba手工介入, 完全由它在运行时自动分配, 这在一定能程度上解放了dba. 也确实起到了提高性能的作用, 比如采用Auto Undo management 能最大限度地降低(非避免) ora-1555发生的几率.
 
数据库关于Automatic undo management 涉及3个数据库参数:

SQL> show parameter undo;

NAME        TYPE  VALUE
------------------------------------ ----------- -----------------------------
undo_management       string  AUTO
undo_retention        integer  900
undo_tablespace       string  UNDOTBS1

1.5.1  Parameter UNDO_MANAGEMENT

UNDO_MANAGEMENT:    当它的值是AUTO时表示启用了, 当值是MANUAL则表示手动管理.
 

1.5.2  Parameter UNDO_TABLESPACE

这个参数制定了回滚表空间, 当UNDO_MANAGEMENT的值是auto时, 可以手动制定这个参数, 指定数据库使用哪个表空间作为undo 表空间.
 
 undo表空间的大小, 直接影响到flashback query 的查询能力, 因为多版本查询依赖的undo数据都存放在undo tablespace中.  该tablespace 越大, 能够存储的undo数据自然就越多, 如果undo tablespace的空间很小, 别说flashback了, 连正常的查询都可能出错.(如果事务DML操作频繁)
 
 

1.5.3  Parameter UNDO_RETENTION

这个参数用来制定undo记录在undo tablespace 内保存的最长时间. 以秒为单位.
这个参数是1个动态参数, dba可以在实例运行时随时修改. 默认是 900秒(15min)
 
指的注意的是,  undo_retention只是制定undo数据的过期时间, 但是并不保证undo数据能在undo tablespace中能保存段时间.
也就是说, 当服务器负载压力大时,  undo数据很可能在undo_retention指定的时间内就被其他undo数据覆盖.
因此, 当dba创建1个自动管理的undo tablespace时, 还要注意其空间大小, 要尽可能保证 undo 表空间内有足够的空间.
 
 
同时, 也并不是说, undo_retention指定的时间已过,  已经提交的事务数据就无法访问.  它只是失效, 只要不被别的事务的undo数据覆盖. flashback仍然可以正常执行. 
 
那么undo_retention是1个多余的参数?  其实只要dba指定的undo tablespace 空间足够大, 而数据库也不是那么繁忙, 这样undo_retention这个参数是不会影响到你的, 哪怕这个参数被设置为1.  总要没有事务去覆盖undo数据, 它就持续有效, 也就是讲, undo tablespace的大小比这个参数重要得多.
 
 

只有1中情况例外,  当为undo tablespace 启用retention guarantee.

oracle 可以保证undo 数据在undo_retention指定的时间内一定存在(不能被其他undo数据覆盖).

启用guarantee:

Alter tablespace undotbs1 retention guarantee;

禁用guarantee:

 Alter tablespace undotbs1 retention noguarantee;

启用这个特性能保证undo数据在undo tablespace 内的存在时间, 但是也有代价的.

假如表空间已满, 而且不允许旧的undo数据被新数据覆盖.   为了保证多版本的读一致性(详见本文第五节), 新的事务的
操作就会受影响了.

所以还是那几句话:  the size of undo tablespace is very importance.

二, Flashback的级别和成员

2.1 Flashback的级别

Flashback可以分为三个级别:

1.Database Level

  数据库级别的flashback允许将数据库恢复到某个时间点,  当误删除1个user或误truncate 1张表是适用数据库级别的flashback.

2.Table level

  表级flashback可以将1个table回滚到某个时间点或者某个SCN号,  也可以闪回通过Drop命令删除的表.

3.Transaction level

  事务级闪回会记录用户事务的每个DML操作, 并给出相应rollback的DML指令. 比如insert操作的rollback指令就是delete.

  一般用于rollback 用户已经commit的误操作事务.

  而根据误操作对于数据的影响.

  用户可以选择执行flashback操作或者flashback查询.(flashback query)

  所谓falshback查询就是查询数据被DML操作的历史记录(一般就是commit的记录), 然后在此基础上确定是否进行flashback操作.

2.2 Flashback的成员

Flashback可以分为如下成员:

1.Flashback Database

2.Flashback Drop

3.Flashback Query

      -- Flashback Query

      -- Flashback Version Query

      -- Flashback Transaction Query

4.Flashback Table

5.Flashback Data Archive

三, Flashback Version Query

首先我们介绍的第一个成员叫flashback 版本查询.

所谓Version是指数据库中每次因为事务commit 而产生的数据行变化情况, 每一次变化就是1个版本.

这里需要强调的是这里变化是因为事务commit 产生的变化, 未commit的事务引起的变化不会被Flashback Version query 检索出来.

Flash Version Query 查询使用的undo 表空间的Undo 数据, 一旦undo数据因为undo segment的空间压力被清除, 则产生无法flashback的情况.

通过versions between 关键字可以查询制定时间(timestamp) or 版本(scn号)区间内的的不同修改版本.

语法:

基于 SCN 的版本查询
SELECT <columns>
FROM <schema_name.table_name>
VERSIONS BETWEEN SCN <minimum_scn>AND <maximum_scn>
[WHERE <column_filter>]
[GROUP BY <non-aggregated_columns>]
[HAVING <group filter>
[ORDER BY <position_numbers_or_column_names>]


基于 TIMESTAMP 的版���查询
SELECT <columns>
FROM <schema_name.table_name>
VERSIONSBETWEEN timestamp to_timestamp('start_timestamp')and to_timestamp('end_timestamp')
[WHERE <column_filter>]
[GROUP BY <non-aggregated_columns>]
[HAVING <group filter>
[ORDER BY <position_numbers_or_column_names>]

返回的视图提供多个伪列. 包括:

VERSIONS_STARTSCN VERSIONS_STARTTIME
记录操作时(也就是产生这条记录)的scn或时间, 如果为空, 表示该行记录是查询范围外创建的.

VERSIONS_ENDSCN VERSIONS_ENDTIME
表示该记录失效时的scn或时间.

这里什么是失效?  所谓失效就是对应的数据行被修改或者删除.

例如事务1中在A时间点修改了数据行x.  那么数据行x在事务1中的starttime 是A,  但是endtime是空的, 因为事务1的修改一直维持.

直到事务2在B时间点再次修改数据行x, 那么数据行x在事务1中的endtime 就是B了, 因为事务1的修改已经失效.

也就是说, 如果这两列的数据是空, 代表在改断时间内无操作(update or delete)

VERSIONS_OPERATION
记录操作的类型, I 表示Insert, D表示Delete, U表示Update.  如果对索引键的update操作, flashback version query可能会表示为Delete和Insert两个动作.

VERSIONS_XID

表示该操作的事务ID(key)

例子:

SQL> create table Test3(id numeric, name varchar2(10));

Table created.

SQL> insert into test3 select 1,'Jack' from dual;

1 row created.

SQL> commit;

Commit complete.

SQL> insert into test3 select 2,'Bill' from dual;

1 row created.

SQL> commit;

Commit complete.

SQL> insert into test3 select 3,'Gordon' from dual;

1 row created.

SQL> commit;

Commit complete.

SQL> update test3 set name = 'Billing' where id = 2;

1 row updated.

SQL> commit;

Commit complete.

SQL> delete from test3 where id = 3;

1 row deleted.

SQL> commit;

Commit complete.

上面例子中我新建1个简单的table Test3, 然后插入了3个数据行, 更新了1条, 删除了1条, 注意的是每条语句后都commit了一次.

接下来可以利用flashback versions query 来查询这张表被修改的版本信息.

select id, name, versions_xid, versions_startscn, versions_endscn,
to_char(versions_starttime,'YY/MM/DD HH24:MI:SS') as startime,
to_char(versions_endtime,'YY/MM/DD HH24:MI:SS') as endtime,
versions_operation
from Test3 versions between scn minvalue and maxvalue where id > 0;

输出:

        ID NAME      VERSIONS_XID    VERSIONS_STARTSCN VERSIONS_ENDSCN STARTIME    ENDTIME          VERSIONS_OPERATION
---------- ---------- ---------------- ----------------- --------------- ----------------- ----------------- ------------------
        3 Gordon    05001400BC090000          3028255                  14/05/22 22:15:47                    D                 
        2 Billing      08001D002B090000          3028245                14/05/22 22:15:23                    U                 
        3 Gordon    020010004A090000          3028239        3028255  14/05/22 22:15:11  14/05/22 22:15:47  I                 
        2 Bill        07000900D5060000          3028234        3028245  14/05/22 22:14:56  14/05/22 22:15:23  I                 
        1 Jack        03000B0068090000          3028229                  14/05/22 22:14:48                    I                 

可以见到:

1. 在倒数第一行, 我们插入了一条数据1,Jack, 它的versions_scn为空, 因为自从insert后一直没有对这条数据行操作.

2. 倒数第2行, 具有version_scn数据, 因为它被倒数第4行的事务更新了(Bill - > Billing).

3. 同样道理, 倒数第3行的Gordon被删除.

相关推荐