Flashback家族二

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flashback家族二相关的知识,希望对你有一定的参考价值。

三、Flashback Query 
正如前言中所提,Flashback Query 是利用多版本读一致性的特性从UNDO 表空间读取操作前的记录数据! 

什么是多版本读一致性 
Oracle 采用了一种非常优秀的设计,通过undo 数据来确保写不堵塞读,简单的讲,不同的事务在写数据时,会将数据的前映像写入undo 表空间,这样如果同时有其它事务查询该表数据,则可以通过undo 表空间中数据的前映像来构造所需的完整记录集,而不需要等待写入的事务提交或回滚。 

flashback query 有多种方式构建查询记录集,记录集的选择范围可以基于时间或基于scn,甚至可以同时查询出记录在undo 表空间中不同事务时的前映象。用法与标准查询非常类似,要通过flashback query 查询undo 中的撤销数据,最简单的方式只需要在标准查询语句的表名后面跟上as of timestamp(基于时间)或as of scn(基于scn)即可。as of timestamp|scn 的语法是自9iR2 后才开始提供支持。 

1、As of timestamp 的示例: 
SQL>  alter session set nls_date_format=‘YYYY-MM-DD hh24:mi:ss‘; 
会话已更改。 
SQL> select sysdate from dual; 
SYSDATE 
------------------- 
2009-10-15 19:04:16 
SQL> select * from A; 
        ID 
        ---------- 
         2 
         1 
         3 
         4 
模拟用户误操作,删除数据 
SQL> delete from A; 
已删除4行。 
SQL> commit; 
提交完成。 
SQL> select * from A; 
未选定行 

查看删除之前的状态: 
假设当前距离删除数据已经有5 分钟左右的话: 
SQL> select * from A as of timestamp sysdate-5/1440; 
        ID 
        ---------- 
         2 
         1 
         3 
         4 
或者: 
SQL>select * from A as of timestamp to_timestamp(‘2009-10-15 19:04:16‘,‘YYYY-MM-DD hh24:mi:ss‘); 
        ID 
        ---------- 
         2 
         1 
         3 
         4 
用Flashback Query恢复之前的数据: 
SQL>Insert into A select * from A as of timestamp to_timestamp(‘2009-10-15 19:04:16‘,‘YYYY-MM-DD hh24:mi:ss‘); 
已创建4行。 
SQL> COMMIT; 
提交完成。 
SQL> select * from A; 
        ID 
        ---------- 
         2 
         1 
         3 
         4 

如上述示例中所表示的,as of timestamp 的确非常易用,但是在某些情况下,我们建议使用as of scn 的方式执行flashback query,比如需要对多个相互有主外键约束的表进行恢复时,如果使用as of timestamp 的方式,可能会由于时间点不统一的缘故造成数据选择或插入失败,通过scn 方式则能够确保记录的约束一致性。 

2. As of scn 示例 
查看SCN: 
SELECT dbms_flashback.get_system_change_number FROM dual; 
SELECT CURRENT_SCN FROM V$DATABASE; 

SQL> SELECT CURRENT_SCN FROM V$DATABASE; 
CURRENT_SCN 
----------- 
1095782 
删除数据: 
SQL> delete from A; 
已删除4行。 
SQL> commit; 
提交完成。 
查看删除之前的状态: 
SQL> select * from A as of scn 1095782; 
        ID 
     ---------- 
         2 
         1 
         3 
         4 
用Flashback Query恢复之前的数据: 
SQL> insert into A select * from A as of scn 1095782; 
已创建4行。 
SQL> commit; 
提交完成。 
SQL> select * from A; 
        ID 
        ---------- 
         2 
         1 
         3 
         4 
事实上,Oracle 在内部都是使用scn,即使你指定的是as of timestamp,oracle 也会将其转换成scn,系统时间标记与scn 之间存在一张表,即SYS 下的SMON_SCN_TIME 

SQL> desc sys.smon_scn_time 
名称                       是否为空? 类型 
----------------------------------------- --------    --------------------------- 
THREAD                               NUMBER 
TIME_MP                              NUMBER 
TIME_DP                              DATE 
SCN_WRP                             NUMBER 
SCN_BAS                              NUMBER 
NUM_MAPPINGS                       NUMBER 
TIM_SCN_MAP                         RAW(1200) 
SCN                                   NUMBER 
ORIG_THREAD                         NUMBER 

每隔5 分钟,系统产生一次系统时间标记与scn 的匹配并存入sys.smon_scn_time 表,该表中记录了最近1440个系统时间标记与scn 的匹配记录,由于该表只维护了最近的1440 条记录,因此如果使用as of timestamp 的方式则只能flashback 最近5 天内的数据(假设系统是在持续不断运行并无中断或关机重启之类操作的话)。 
注意理解系统时间标记与scn 的每5 分钟匹配一次这句话,举个例子,比如scn:339988,339989 分别匹配08-05-3013:52:00 和2008-13:57:00,则当你通过as of timestamp 查询08-05-30 13:52:00 或08-05-30 13:56:59 这段时间点 
内的时间时,oracle 都会将其匹配为scn:339988 到undo 表空间中查找,也就说在这个时间内,不管你指定的时间点是什么,查询返回的都将是08-05-30 13:52:00 这个时刻的数据。 
查看SCN 和 timestamp 之间的对应关系: 
select scn,to_char(time_dp,‘yyyy-mm-dd hh24:mi:ss‘)from sys.smon_scn_time; 
Flashback version Query 
相对于Flashback Query 只能看到某一点的对象状态, Oracle 10g引入的Flashback Version Query可以看到过去某个时间段内,记录是如何发生变化的。 根据这个历史,DBA就可以快速的判断数据是在什么时点发生了错误,进而恢复到之前的状态。 
先看一个伪列 ORA_ROWSCN.  所谓的伪列,就是假的,不存在的数据列,用户创建表时虽然没有指定,但是Oracle为了维护而添加的一些内部字段,这些字段可以像普通文件那样的使用。 
最熟悉的伪列就是 ROWID, 它相当于一个指针,指向记录在磁盘上的位置。ORA_ROWSCN 是Oracle 10g 新增的,暂且把它看作是记录最后一次被修改时的SCN。 Flashback Version Query 就是通过这个伪列来跟踪出记录的变化历史。 
举个例子: 
SQL> select * from A; 
        ID 
        ---------- 
         2 
         1 
         3 
         4 
SQL> insert into A values(5); 
已创建 1 行。 
SQL> select * from A; 
        ID 
        ---------- 
         2 
         1 
         3 
         4 
         5 
SQL> commit; 
提交完成。 
SQL> select ora_rowscn, id from A; 
ORA_ROWSCN       ID 
----------             ---------- 
   1098443          2 
   1098443          1 
   1098443          3 
   1098443          4 
   1098443          5 
获取更多的历史信息 
SQL>Select versions_xid,versions_startscn,versions_endscn, 
   DECODE(versions_operation,‘I‘,‘Insert‘,‘U‘,‘Update‘,‘D‘,‘Delete‘, ‘Original‘) "Operation", id from A versions between scn minvalue and maxvalue; 
或者 
SQL>select xid,commit_scn,commit_timestamp,operation,undo_sql 
from flashback_transaction_query q where q.xid in(select versions_xid from B versions between scn 413946 and 413959); 
VERSIONS_XID     VERSIONS_STARTSCN VERSIONS_ENDSCN Operatio    ID 
---------------- ----------------- --------------- -------- ---------- 
05001A0054020000           1099482                 Update            3 
05001A0054020000           1099482                 Delete            3 
05001A0054020000           1099482                 Delete            2 
05001A0054020000           1099482                 Delete            1 
0400150005020000           1098443                 Insert             5 
下面我们来讲下伪列, Flashback Version Query 技术其实有很多伪列,但是ORA_ROWSCN是最重要。它记录的是最后一次被修改时的SCN, 注意是被提交的修改。如果没有提交,这个伪列不会发生变化。 
ORA_ROWSCN 缺省是数据块级别的,也就是一个数据块内的所有记录都是一个ORA_ROWSCN,数据块内任意一条记录被修改,这个数据库块内的所有记录的ORA_ROWSCN都会同时改变。上例的查询结果以证明。 
不过我们可以在建表时使用关键字 rowdependencies, 可以改变这种缺省行为,使用这个关键字后,每条记录都有自己的ORA_ROWSCN。 
举例: 
SQL> create table B (id number(2)) rowdependencies; 
表已创建。 
SQL> insert into B values(1); 
已创建 1 行。 
SQL> insert into B values(2); 
已创建 1 行。 
SQL> insert into B values(3); 
已创建 1 行。 
SQL> commit; 
提交完成。 
SQL> select ora_rowscn, id from B; 
ORA_ROWSCN         ID 
---------- ---------- 
   1100560          1 
   1100560          2 
   1100560          3 
此处SCN一样,一定很奇怪,这正好说明是最后一次被修改时的SCN,如果没有提交,是不会变的,我们重做一下就清楚了。 
SQL> analyze table B compute statistics; 
表已分析。 
SQL> select ora_rowscn, id from B; 
ORA_ROWSCN         ID 
---------- ---------- 
   1100560          1 
   1100560          2 
   1100560          3 
SQL> delete from B; 
已删除4行。 
SQL> select ora_rowscn, id from B; 
未选定行 
SQL> insert into B values(1); 
已创建 1 行。 
SQL> commit; 
提交完成。 
SQL> insert into B values(2); 
已创建 1 行。 
SQL> commit; 
提交完成。 
SQL> select ora_rowscn, id from B; 
ORA_ROWSCN         ID 
---------- ---------- 
   1100723          1 
   1100729          2 
Flashback Transaction Query 
Flashback Transaction Query也是使用UNDO信息来实现。利用这个功能可以查看某个事务执行的所有变化,它需要访问flashback_transaction_query 视图,这个视图的XID列代表事务ID,利用这个ID可以区分特定事务发生的所有数据变化。 
示例: 
SQL> insert into B values(3); 
已创建 1 行。 
SQL> commit; 
提交完成。 
SQL> select * from B; 
        ID 
       ---------- 
         1 
         2 
         3 
查看视图,每个事务都对应相同的XID 
SQL>Select xid,operation,commit_scn,undo_sql from flashback_transaction_query where xid in ( 
Select versions_xid from B versions between scn minvalue and maxvalue); 
或者 
SQL>select xid,commit_scn,commit_timestamp,operation,undo_sql 
from flashback_transaction_query q where q.xid in(select versions_xid from B versions between scn 413946 and 413959); 
XID              OPERATION                        COMMIT_SCN 
---------------- -------------------------------- ---------- 
UNDO_SQL 
-------------------------------------------------------------------------------- 
03001C006A020000 DELETE                              1100723 
insert into "SYS"."B"("ID") values (‘4‘); 
03001C006A020000 DELETE                              1100723 
insert into "SYS"."B"("ID") values (‘3‘); 
03001C006A020000 DELETE                              1100723 
insert into "SYS"."B"("ID") values (‘2‘); 


四、Flashback Table 
注意SYS用户不支持闪回,这点前面已经说明过。 
Flashback Table也是使用UNDO tablespace的内容来实现对数据的回退。该命令相对简单,输入:flashback table table_name to scn(to timestamp) 即可。 
注意:如果想要对表进行flashback,必须允许表的row movement. 
Alter table table_name row movement; 
要查看某表是否启用row movement,可以到user_tables 中查询(或all_tables,dba_tables), 
例如: 
SQL> select row_movement from user_tables where table_name=‘C‘; 
ROW_MOVE 
-------- 
ENABLED 

要启用或禁止某表row movement,可以通过下列语句: 

--启用 
JSSWEB> ALTER TABLE table_name ENABLE ROW MOVEMENT; 
表已更改。 
--禁止 
JSSWEB> ALTER TABLE table_name DISABLE ROW MOVEMENT; 
表已更改。 
举例: 
SQL> create table C (id number(2)); 
表已创建。 
SQL> insert into C values(1); 
已创建 1 行。 
SQL> insert into C values(2); 
已创建 1 行。 
SQL> commit; 
提交完成。 
SQL> select * from c; 
        ID 
---------- 
         1 
         2 
SQL> alter session set nls_date_format="yyyy-mm-dd hh24:mi:ss"; 
会话已更改。 
SQL> select sysdate from dual; 
SYSDATE 
------------------- 
2009-10-15 21:17:47 
SQL> select current_scn from v$database; 
CURRENT_SCN 
----------- 
      1103864 
删除数据并恢复 
SQL> delete from C; 
已删除2行。 
SQL> commit; 
提交完成。 
SQL> alter table c enable row movement; 
表已更改。 
SQL> flashback table c to scn  1103864; 
闪回完成。 
或者: 
SQL> flashback table c to timestamp to_timestamp(‘2009-10-15 21:17:47‘,‘yyyy-mm- 
dd hh24:mi:ss‘); 
SQL> select * from c; 
        ID 
---------- 
         1 
         2 
Flashback table 命令支持同时操作多个表,表名中间以逗号分隔即可,如果你执行一条flashback table命令时同时指定了多个表,要记住单个flashback table 是在同一个事务中,因此这些表的恢复操作要么都成功,要么都失败。 
如: 
flashback table a,b ,c to scn 1103864; 
一些注意事项 

1. 基于undo 的表恢复,需要注意DDL 操作的影响 
第三个就是修改并提交过数据之后,对表做过DDL 操作,包括: 
drop/modify 列, move 表, drop 分区(如果有的话), truncate table/partition,这些操作会另undo 表空间中的撤销数据失效,对于执行过这些操作的表应用flashback query 会触发ORA-01466 错误。另外一些表结构修改语句虽然并不会影响到undo 表空间中的撤销记录,但有可能因表结构修改导致undo 中重做记录无法应用的情况,比如对于增加了约束,而flashback query 查询出的undo 记录已经不符合新建的约束条件,这个时候直接恢复显然不可能成功,你要么暂时disable 约束,要么通过适当逻辑,对要恢复的数据进行处理之后,再执行恢复。 
另外,flashback query 对v$tables,x$tables 等动态性能视图无效,不过对于dba_*,all_*,user_*等数据字典是有效的。同时该特性也完全支持访问远端数据库,比如select * from [email protected] as of scn 360;的形式。 

2. 基于undo 的表恢复,flashback table 实际上做的也是dml 操作(会在被操作的表上加dml 锁),因此还需要注意triggers 对其的影响,默认情况下,flashback table to scn/timestamp 在执行时会自动disable 掉与其操作表相差的triggers,如果你希望在此期间trigger 能够继续发挥做用,可以在flashback table 后附加 
ENABLE TRIGGERS 子句。 

补充: 

什么是Automatic Undo Management( 自动撤销管理表空间) 
提到自动撤销管理表空间,就不得不提手动管理的回滚段。在9i 之前,回滚段的管理和监控是需要dba手工介入的,创建合适的回滚段是件非常耗费dba 精力的事情,你可能需要不断关注oracle 运行状况很长一阵子时间后,通过不断的调整才能基本确认一段时期内回滚段的大小,一旦回滚段创建的不合适,就极有可能引起性能问题甚至错误,比如ora-1555 就是典型的回滚段设置不合适触发的。 
9i 之后呢(含9i),oracle 为了清晰它的整个概念,取消了回滚段这个说法(实际上并未取消回滚段),而完全以undo 来代替,这也它正好与redo 相对应,一个重做,一个撤销。回滚段可以不再由dba 手工介入,而是完全由它自己在运行时自动分配,这在一定程度上即解放了dba,也确实起到了提高性能的作用,比如采用自动管理表空间就可以最大程序的降低ora-1555发生的机率(注意是降低,不是避免,我们不可能创建一个无限大的回滚段,ora-1555 也并不完全是回滚段造成的,关于ora-1555 的问题这里就不深入讨论了,互联网上已经有太多文章描述和介绍该问题及解决方案) 
是否起用自动管理的撤销表空间由二个初始化参数决定: 
UNDO_MANAGEMENT:值为AUTO 表示使用了自动撤销管理表空间,MANUAL 则表示手动管理 
UNDO_TABLESPACE:当UNDO_MANAGEMENT 值为AUTO 时,该参数用来指定当前的undo 表空间名称。 
undo 表空间的大小,直接影响到flashback query 的查询能力,因为多版本查询所依赖的undo 数据都存储在undo 表空间中,该表空间越大,所能够存储的undo 数据自然也越多,如果该表空间可用空间非常小,别说flashback 了,恐怕正常查询都有可能触发ora-1555 吧。 

初始化参数UNDO_RETENTION 
该参数用来指定undo 记录保存的最长时间,以秒为单位,是个动态参数,完全可以在实例运行时随时修改通常默认是900 秒,也就是15 分钟。 
一定要注意,undo_retention 只是指定undo 数据的过期时间,并不是说,undo 中的数据一定会在undo表空间中保存15 分钟,比如说刚一个新事务开始的时候,如果undo 表空间已经被写满,则新事务的数据会自动覆盖已提交事务的数据,而不管这些数据是否已过期,因此呢,这就又关联回了第一点,当你创建 
一个自动管理的undo 表空间时,还要注意其空间大小,要尽可能保证undo 表空间有足够的存储空间。 
同时还要注意,也并不是说,undo_retention 中指定的时间一过,已经提交事务中的数据就立刻无法访问,它只是失效,只要不被别的事务覆盖,它会仍然存在,并可随时被flashback 特性引用。如果你的undo表空间足够大,而数据库又不是那么繁忙,那么其实undo_retention 参数的值并不会影响到你,哪怕你设置成1,只要没有事务去覆盖undo 数据,它就会持续有效。因此呢,这里还是那句话,要注意undo 表空间的大小,保证其有足够的存储空间。 

只有在一种情况下,undo 表空间能够确保undo 中的数据在undo_retention 指定时间过期前一定有效,就是为undo 表空间指定Retention Guarantee,指定之后,oracle 对于undo 表空间中未过期的undo 数据不会覆盖, 
例如: 
SQL> Alter tablespace undotbs1 retention guarantee; 
如果想禁止undo 表空间retention guarantee, 
例如: 
SQL> Alter tablespace undotbs1 retention noguarantee;


以上是关于Flashback家族二的主要内容,如果未能解决你的问题,请参考以下文章

MySQL Flashback功能测试

Oracle Flashback 详解

Oracle Flashback闪回恢复管理_超越OCP精通Oracle视频课程培训20

[Oracle维护工程师手记系列]为什么flashback 的时候既需要 flashback log ,又需要 archive log?

Oracle Flashback和RMAN示例

mysqlbinlog flashback 5.6版本