阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Oracle Flashback(闪回) 详解

103次阅读
没有评论

共计 35352 个字符,预计需要花费 89 分钟才能阅读完成。

通常我们对数据库进行了误操作时, 需要把数据库 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 被删除.

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-12/138187p2.htm

四, Flashback Transaction Query

上面的 flash versions query 可以查出事务的操作时间, xid 等关键信息.

而通过 Flash Transaction Query 则可以利用 xid 来获得回滚的 sql statement. 用户可以根据需要利用这些 undo sql 来回滚数据.

所以 Flash Transaction Query 实际上是 Flash versions query 的扩展. 通常会配合使用.

例子:

例用上面的表, 新插入两条重复的数据.

SQL> insert into test3 select 4, ‘Paula’ from dual;

1 row created.

SQL> commit;

Commit complete.

SQL> insert into test3 select 4, ‘Paula’ from dual;

1 row created.

SQL> commit;

Commit complete.

通过 Flash versions query 可以查询到 xid:

select id, name, versions_xid
from Test3 versions between scn minvalue and maxvalue where id > 3;

        ID NAME      VERSIONS_XID 
———- ———- —————-
        4 Paula      01001800D8060000
        4 Paula      030013006A090000

而通过 Flash transaction query 则可以获得回滚 sql.

select operation, undo_sql from flashback_transaction_query
where xid in (select versions_xid from Test3 versions between scn minvalue and maxvalue where id > 3)

输出:

OPERATION                        UNDO_SQL                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
——————————– ————————————————————————————————
INSERT                          delete from “BILL”.”TEST3″ where ROWID = ‘AAASf4AAFAAACkXAAE’;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
BEGIN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
INSERT                          delete from “BILL”.”TEST3″ where ROWID = ‘AAASf4AAFAAACkXAAD’;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
BEGIN   

可以见到, insert 语句的 Undo sql 是 delete 语句, 而且是用 Rowid 来作为 condition 的 所以, 即使我插入两条完全相同的数据行, 也可以正确地回滚.

五, Flashback Query

接下来是 Flash Query.

上面介绍的 Flash versions query 和 Flash transaction query 都是查看每个 commited 的事务具体信息.

而 Flash Query 是查看某张 table 在某个时刻的数据镜像, 依赖于 undo 表空间的 undo 数据.

一旦我们发现某个时间的数据满足我们的需求之后, 我们就可以例用该镜像来回滚整张 table.

Flashback Query 利用 多版本读一致性 从 undo tablesapce 读取操作前的记录数据. 可以用于进来数据对比或覆盖回滚.

所谓多版本读一致性就是:

Oracle 采用了一种设计, 同过 undo 数据来保证写操作不影响读操作.  简单地讲, A 事务正在写数据时, 回将数据的前映像写入 undo 表空间, 如果 B 事务读取同样的数据, 则会读到 undo 表空间的正确数据, 而不需要等 A 事务 commit or rollbak.  这样保证了 B 事务不会读到 A 事务未就提交的数据.

Flashback Query 有多种方式构建查询 recordset, 其选择范围可以基于时间(As of timpstamp) or 基于 scn(As of scn).

语法:

使用 as of scn
SELECT <column_name_list>
FROM <table_name>
AS OF <SCN>
[WHERE <filter_conditions>]
[GROUP BY <unaggregated columns>]
[HAVING <group_filter>]
[ORDER BY <column_positions_or_name>]

使用 as of timestamp
SELECT <column_name_list>
FROM <table_name>
AS OF <TIMESTAMP>
[WHERE <filter_conditions>]
[GROUP BY <unaggregated columns>]
[HAVING <group_filter>]
[ORDER BY <column_positions_or_name>]

5.1 As of timestamp 例子:

继续用上面的表 test3 做例子:
 

SQL> select sysdate from dual;

SYSDATE
——————-
2014-05-24 22:44:21

SQL> select * from test3;

 ID NAME
———- ———-
  1 Jack
  2 Billing
  4 Paula
  4 Paula

SQL> select sysdate from dual;

SYSDATE
——————-
2014-05-24 22:46:16

SQL> update test3 set name = ‘Jason’;

4 rows updated.

SQL> commit;

Commit complete.

SQL> select sysdate from dual;

SYSDATE
——————-
2014-05-24 22:48:30

SQL> delete from test3;

4 rows deleted.

SQL> commit;

Commit complete.

解析:

1. 在 22:44 时, Test3 表里有 4 行数据.

2. 在 22:46 时, 把 Test3 表全部更新成 name = Jason

3. 在 22:48 时, 删除所有记录(模拟误删除).

假如当前时间是 22:50 ,  操作者想查看 6 分钟前和 3 分钟前的表映像:

SQL> select sysdate from dual;

SYSDATE
——————-
2014-05-24 22:50:54

SQL> select * from test3 as of timestamp sysdate – 6/1440;

 ID NAME
———- ———-
  1 Jack
  2 Billing
  4 Paula
  4 Paula

SQL> select * from test3 as of timestamp sysdate – 3/1440;

 ID NAME
———- ———-
  1 Jason
  2 Jason
  4 Jason
  4 Jason

假如操作者想把表恢复成 6 分钟前的版本

则配合 insert 操作就 ok 了, 注意下面 timestamp 就制定了具体值, 大概 22:44 .

SQL> insert into test3 select * from test3 as of timestamp to_timestamp(‘2014-05-24 22:44:05′,’YYYY-MM-DD hh24:mi:ss’);

4 rows created.

SQL> commit;

Commit complete.

SQL> select * from test3;

 ID NAME
———- ———-
  1 Jack
  2 Billing
  4 Paula
  4 Paula

上面例子, 表明 as of timestamp 的确非常易用, 但是大部分情况吓, 我们建议使用 as of scn 来执行 flashback query.

因为需要对多个有主外键约束的表进行恢复时, 如果使用 as of  timestamp 可能因为时间点不统一而导致插入失败.

5.2 As of scn 例子:

上面例子我们利用

select sysdate from dual;

来获得数据库当前时间.

相应地, 我们可以利用

select current_scn from v$database;

来获得数据库的当前 scn, 注意必须具有 select any dictionary 的权限

下面是例子:

首先获得当前数据库 scn

然后删除 test3 所有数据行:

SQL> select current_scn from v$database;

CURRENT_SCN
———–
    3088322

SQL> delete from test3;

4 rows deleted.

SQL> commit;

Commit complete.

然后利用 as of scn flashback query 来获得具体 scn 时的 test3 映像:

SQL> select * from test3 as of scn 3088322;

 ID NAME
———- ———-
  1 Jack
  2 Billing
  4 Paula
  4 Paula

配合 insert into 语句恢复表数据:

SQL> select * from test3 as of scn 3088322;

 ID NAME
———- ———-
  1 Jack
  2 Billing
  4 Paula
  4 Paula

SQL> insert into test3 select * from test3 as of scn 3088322;

4 rows created.

SQL> commit;

Actually, 无论用户使用 as of timestamp or scn, oracle 在底层都是使用 scn.  也就是 oracle 具有 1 个把 timestamp 转换成 scn 的机制.

oracle 里有一张表来表示 timestamp 和 scn 的对应关系. 这张表就是 sys.smon_scn_time.

oracle 每隔 5 分钟, 系统产生一次系统时间标记与 scn 的匹配记录并存入 sys.smon_scn_time.

值得注意的时, 也就是在这 5 分钟所有的时间都是匹配同 1 个 scn.   也就是说使用 as of timestamp  5 分钟内的不同 timpstamp 实际上都是指向同 1 个 scn..

可以用如下语句来查看 scn 和 timestamp 之间的对应关系:

select scn,to_char(time_dp,’yyyy-mm-dd hh24:mi:ss’) from sys.smon_scn_time;

5.3 伪列 ORA_ROWCN

     Oracle 为了方便维护会为数据表添加一些内部字段, 我们最熟悉的伪列就是 ROWID. 啦.  而 ora_rowscn 是 oracle 10g 新增的, 暂且可以把它看做是数据行最后一次被修改的 scn.  Flash version query 就是通过这个伪列来 trace 数据行变化的历史.
 
例子:

SQL> select ora_rowscn, id , name from test3;

ORA_ROWSCN    ID NAME
———- ———- ———-
  3088585    1 Jack
  3088585    2 Billing
  3088585    4 Paula
  3088585    4 Paula

SQL> select current_scn from v$database;

CURRENT_SCN
———–
    3101850

SQL> update test3 set name = ‘Calvin’ where id = 2;

1 row updated.

SQL> select ora_rowscn, id , name from test3;

ORA_ROWSCN    ID NAME
———- ———- ———-
  3088585    1 Jack
  3088585    2 Calvin
  3088585    4 Paula
  3088585    4 Paula

SQL> commit;

Commit complete.

SQL> select ora_rowscn, id , name from test3;

ORA_ROWSCN    ID NAME
———- ———- ———-
  3101948    1 Jack
  3101948    2 Calvin
  3101948    4 Paula
  3101948    4 Paula

上面的例子, 我只更新了 1 个数据行, 但是所有行的 ora_rowscn 都被更新了?

实际上, ora_rowscn 默认是数据块(block) 级别的, 也就是说在同 1 个 block 中所有数据行都是同 1 个 ora_rowscn. block 中任意一行被修改, 该 block 中所有数据行的 ora_rowscn 都会被刷新.

可以在建表时使用 keyword  rowdependencies, 可以改变 ora_rowscn 的默认 level, 令每一数据行都有独立的 ora_rowscn.

通常我们对数据库进行了误操作时, 需要把数据库 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 被删除.

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-12/138187p2.htm

六, Flashback Table

上面及介绍的 flashback query 能够查看一张表的在历史上某个时间点的映像.  但是如果要回滚的话要配合 delete 和 insert 操作.
 

而 Flashback Table 能 直接 将表里的数据 rollback 到历史上的某个时间点.  如果 rollback 到用户误删除数据之前的时间点, 则回把误删除的数据行恢复.  在这个过程中, 数据库仍然是在线可用的.    

Flashback Table 也是利用 undo 表空间的旧数据. 假如所需的 undo 数据由于保留的时间超过了初始化参数 undo_retention 所指定的值. 从而被其他事务覆盖掉的话, 就有可能恢复失败.

Flashback table 操作会修改表里的数据, 从而有可能引起 data rows 的行移动,  比如某一行 datarow 当前在 A block 中, 而在表闪回到以前的某个时间点上市, 在那个时间点那个 datarow 在 B block 中, 那么在执行 Flashback table 前必须启用数据行的移动特性.

Alter table <table_name> enable row movement;

Oracle 11g Flashback table 的特性:

1、在线操作;
2、恢复到指定时间点或 SCN  或 储存点 (restore point) 的任何数据;
3、自动恢复相关属性、如索引、触发器等 ( 但是删除的索引, trigger 不能通过 flashback table 来恢复 )
4、满足分布式的一致性;
5、满足数据一致性, 所有相关对象将自动一致;
6、闪回表技术是基于回滚数据(undo data) 来实现的, 因此, 要想闪回表到过去的某
个时间上, 必须确保与回滚表空间有关的参数设置合理。

语法:

Flashback table <table_name> to SCN <scn_number> [<ENABLE|DISABLE> TRIGGERS]

Flashback table <table_name> to Timestamp <scn_number> [<ENABLE|DISABLE> TRIGGERS]

注意的是, Flashback Table 可以向前 Flashback, 一旦执行向前 Flashback 后也可以执行向后 flashback. 而 Sys schema 下的 table 不能执行 Flashback table 操作.

6.1 Flashback table 的一些特性和注意事项

Flashback table 命令作为单独的 1 个事务执行, 获取 DML 锁, 统计信息不会被闪回;  当前的索引和依赖对象会被维护.
具有如下特性:
 
1. 不能对系统表执行 flashback table 操作.   sys schema 下的表不支持 flashback table.
2. 在执行 DDL 操作后不能执行向前的 flashback 操作. (例如增删数据列, 增加约束)

3. Flashback table 操作会被写入 alert 日志文件.

4. Flashback table 操作会产生 undo 和 redo 数据.

5. flashback query 对 v$tables,x$tables 等动态性能视图无效, 不过对于 dba_*,all_*,user_* 等数据字典是有效的

6. 执行 delete(不是 drop)的操作的表也可以被 flashback table 恢复, 但是被 truncate 操作的表是不能被 flashback table 恢复的. 因为它使用 undo 数据.

基于 undo 的表恢复, flashback table 实际上做的也是 dml 操作(会在被操作的表上加上 dml 锁), 因此还需注意 triggers 的影响.

此时可以在后面附加 ENABLE | DISABLE TRIGGERS 字句来 handle.

6.2 Flashback table 的例子:

6.2.1 基于 TIMESTAMP 的 FlashBack

1. 首先创建两张相同内容的表 t1 和 t2

SQL> drop table t2;

Table dropped.

SQL> create table t1 as select * from user_objects;

Table created.

SQL> create table t2 as select * from t1;

Table created.

SQL> select sysdate from dual;

SYSDATE
——————-
2014-05-25 12:10:50

2. 为表 t1 创建两个 indexes

SQL> create index idx1_t1 on t1(object_name);

Index created.

SQL> create index idx2_t1 on t1(object_id);

Index created.

SQL> select sysdate from dual;

SYSDATE
——————-
2014-05-25 12:14:30

3. 删除 1 个 index, 删除其中 t1 所有数据行, truncate t2.

SQL> drop index idx1_t1;

Index dropped.

SQL> delete from t1;

11 rows deleted.

SQL> commit;

Commit complete.

SQL> truncate table t2;

Table truncated.

SQL> select sysdate from dual;

SYSDATE
——————-
2014-05-25 12:16:52

4. 查看 row movement 状态并启用 t1 和 t2 的 row movement 属性.

SQL> select table_name, row_movement from user_tables where table_name in (‘T1′,’T2’);

TABLE_NAME        ROW_MOVE
—————————— ——–
T1          DISABLED
T2          DISABLED

SQL> alter table t1 enable row movement;

Table altered.

SQL> alter table t2 enable row movement;

Table altered.

SQL> select table_name, row_movement from user_tables where table_name in (‘T1′,’T2’);

TABLE_NAME        ROW_MOVE
—————————— ——–
T1          ENABLED
T2          ENABLED

5. 对 t1 执行 flashback 操作, 可以看到所有被删除的数据行都被恢复了, 但是 drop 掉的索引无法恢复.

SQL> flashback table t1 to timestamp to_timestamp(‘2014-05-25 12:13:00′,’yyyy-mm-dd hh24:mi:ss’);

Flashback complete.

SQL> select count(1) from t1;

  COUNT(1)
———-
 11

SQL> select index_name, table_name from  user_indexes;

INDEX_NAME        TABLE_NAME
—————————— ——————————
IDX2_T1         T1

6. 尝试 flashback table for t2 失败, 因为被 truncate 的表无法通过 flashback table 恢复.

SQL> flashback table t2 to timestamp to_timestamp(‘2014-05-25 12:14:00′,’yyyy-mm-dd hh24:mi:ss’);
flashback table t2 to timestamp to_timestamp(‘2014-05-25 12:14:00′,’yyyy-mm-dd hh24:mi:ss’)
                *
ERROR at line 1:
ORA-01466: unable to read data – table definition has changed

SQL> select count(1) from t2;

  COUNT(1)
———-
  0

6.2.2 基于 restore point 的 flashback table

1. 下面我创建 3 个 restore point, 分别对应插入 3 条数据行到表 test3.

SQL> select * from test3;

 ID NAME
———- ———-
  1 Jack
  2 Calvin
  4 Paula
  4 Paula

SQL> create restore point zero;

Restore point created.

SQL> insert into test3 select 5,’Alice’ from dual;

1 row created.

SQL> commit;

Commit complete.

SQL> create restore point one;

Restore point created.

SQL> insert into test3 select 6,’Hebe’ from dual;

1 row created.

SQL> commit;

Commit complete.

SQL> create restore point two;

Restore point created.

SQL> insert into test3 select 7, ‘Ella’ from dual;

1 row created.

SQL> commit;

Commit complete.

SQL> select * from test3;

 ID NAME
———- ———-
  1 Jack
  2 Calvin
  4 Paula
  4 Paula
  7 Ella
  5 Alice
  6 Hebe

7 rows selected.

2. 对 test3 执行恢复到 restore point two, 在其后插入的数据行 7, Ella 没有恢复.

SQL> alter table test3 enable row movement;

Table altered.

SQL> flashback table test3 to restore point two;

Flashback complete.

SQL> select * from test3;

 ID NAME
———- ———-
  1 Jack
  2 Calvin
  4 Paula
  4 Paula
  5 Alice
  6 Hebe

6 rows selected.

SQL> drop restore point one;

Restore point dropped.

SQL> drop restore point zero;

Restore point dropped.

SQL> drop restore point two;

Restore point dropped.

6.2.3 对于具有 fk 约束关系的两个表一同恢复.

1, 创建两张表 t3, t4,

SQL> create table t3 enable row movement as select * from scott.emp;

Table created.

SQL> create table t4 enable row movement as select * from scott.dept;

Table created.

SQL> select current_scn from v$database;

CURRENT_SCN
———–
    3108694

2. 为这两张表添加 pk 及 fk 约束.

SQL> alter table t3 add constraint  t3_empno_pk primary key(empno);

Table altered.

SQL> alter table t4 add constraint  t4_deptno_pk primary key(deptno);

Table altered.

SQL> alter table t3 add constraint t3_t4_deptno_fk foreign key(deptno) references t4(deptno);

Table altered.

 3. 对应先后删除 t3 和 t4 部门号码是 20 的数据.

SQL> select empno, deptno from t3 where deptno = 10;

    EMPNO    DEPTNO
———- ———-
      7782    10
      7839    10
      7934    10

SQL> select current_scn from v$database;

CURRENT_SCN
———–
    3109085

SQL> delete from t3 where deptno = 10;

3 rows deleted.

SQL> delete from t4 where deptno = 10;

1 row deleted.

SQL> commit;

Commit complete.

4. 尝试单独恢复 t3 到数据删除前, get 到 error, 因为约束关系 (当前 t4 不存在部门号码 =20) 的数据.

SQL> flashback table t3 to scn 3109085;
flashback table t3 to scn 3109085
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02291: integrity constraint (BILL.T3_T4_DEPTNO_FK) violated – parent key
not found

5. t3, t4 一起恢复就 ok 了!

SQL> flashback table t3,t4 to scn 3109085;

Flashback complete.

6. 检查数据, 部门号码为 20 的数据已被恢复:

SQL> select t3.empno, t4.deptno from t3, t4 where t4.deptno = t3.deptno and t4.deptno = 10;

    EMPNO    DEPTNO
———- ———-
      7782    10
      7839    10
      7934    10

���, Flashback Drop

通过上面的介绍以及例子, 相信大家都知道 flashback table 能恢复被删除 /or 被修改的数据行.

但是不能恢复被 drop 掉的 index, 更别说恢复被 drop 掉的表了.

如果想恢复被 drop 掉的对象. oracle 提供另 1 个 flashback 成员, 就是 Flashback drop.

语法:  

跟上面的 Flashback table 很类似, 只不过 to 后面不再是 scn or timestamp, 而是 before drop

Flashback table <table_name> to before drop;

在没有 flashback 技术之前, 如果想恢复用户唔删除的表和对象. 只能使用传统的数据恢复方式从备份中恢复. 

有了 flashback 之后, 当用户使用 drop table 删除一张表时, 该表并不会在数据库中立即删除, 而是保持原表的位置. 但是将删除的表重新命名, 并将删除的表的信息存储在回收站中, 回收占记录了被删除的表的新名字和旧名字. 显然此时被删除的表所占的空间没有被立即释放, 变成数据库可以使用的潜在空间. 记录在回收站的信息会保留一段时间, 知道回收站空间不足或使用 purge 指令删除回收站中的记录.

   回收站是 1 个逻辑结构, 不具有物理数据结构, 只要删除的表信息记录在回收站, 就可以通过 flashback 来恢复被 drop 的表. 每个表空间都有 1 个叫做回收站 (recyclebin) 的逻辑区域.  

    也就是讲: 跟上面 flashback 成员不同, drop 掉的表 or 其他对象, 并没有 undo 数据被放入到 Undo tablespace 内, 而是存在于对象原本的表空间的回收站内.

     Oracle 回收站将用户所做的 drop 语句操作记录在一个系统表内. 即将被删除的对象写到 1 个数据字典中, 当不在需要被删除的对象时, 可以使用 purge 命令队回收站空间进行清除.  

     但是此时被删除的表原被所占物理数据块会被标记成可以用, 也就是说可以被其他新数据所覆盖.  而在这种事情发生之前, 用户就可以利用 flashback 从回收站中恢复被误删除的表.

   当 1 个被 drop 掉的表被 flashback 恢复时, 这张表的约束, 包括 pk, ui, not null 都会被恢复.  但是外键约束不会被恢复, 需要手动添回.

    我们可以通过如下命令来查看系统中回收站是否被启用:

SQL> show parameter recyclebin

NAME        TYPE  VALUE
———————————— ———– ——————————
recyclebin        string  on
SQL>

也可以禁用 / 启用 回收站, 当然一旦禁用, flashback drop 将无法生效

alter system/session  set recyclebin=on|off;

 使用如下命令清空回收站(当前用户)

SQL> purge user_recyclebin;

Recyclebin purged.

7.1 Flashback drop 的例子:

继续用上面的 t3 表作例子:

SQL> select constraint_name, constraint_type, table_name from user_constraints where table_name = ‘T3’;

CONSTRAINT_NAME         C TABLE_NAME
—————————— – ——————————
T3_EMPNO_PK        P T3
T3_T4_DEPTNO_FK         R T3

SQL> select count(1) from t3;

  COUNT(1)
———-
 14

可见此时 T3 具有 1 个主键和外键约束.

1.drop 掉表 T3

SQL> drop table t3;

Table dropped.

2. 查看回收站, 见到有一条关于 T3 的记录:

SQL> show recyclebin;
ORIGINAL NAME  RECYCLEBIN NAME  OBJECT TYPE  DROP TIME
—————- —————————— ———— ——————-
T3  BIN$+jNxn7Lfw3XgQAB/AQApBg==$0 TABLE      2014-05-25:15:04:55

记录中还包括 drop 的时间哦.

3. 使用 flashback drop 恢复表 T3

SQL> flashback table t3 to before drop;

Flashback complete.

4. 这时检查 T3, 发现所有数据行被恢复, 主键也被恢复(被 renamed 哦), 但是外键就被丢失了.

SQL> select count(1) from t3;

  COUNT(1)
———-
 14

SQL> select constraint_name, constraint_type, table_name from user_constraints where table_name = ‘T3’;

CONSTRAINT_NAME         C TABLE_NAME
—————————— – ——————————
BIN$+jNxn7Ldw3XgQAB/AQApBg==$0 P T3

八, 小结

本文着重介绍了几个成员,  但是还有一些不常用的成员例如 flashback database(例如恢复被删除的用户)就不详细介绍了.
希望本文能帮助你明白 flashback 的原理以及简单用法.

本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-12/138187.htm

正文完
星哥说事-微信公众号
post-qrcode
 
星锅
版权声明:本站原创文章,由 星锅 2022-01-22发表,共计35352字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中