1撤销的作用
撤销数据是反转DML语句结果所需的信息。撤销数据通常被称为“回滚数据”,在过去的Oracle版本中,“回滚数据”和“撤销数据”可以交替使用,但从9i版本开始,这两个术语有所不同:功能相同,但管理方式不同。只要某个事务修改了数据,那么更新前的原有数据就会被写入一个回滚段或撤销段。回滚段在11g版本中依然存在,但从9i版本开始,Oracle数据库引入了可供选择的撤销段。Oracle强烈建议所有数据库都应当使用撤销段,回滚段只被保留用于向后兼容。为了满足ACID测试的要求,回滚通常是自动完成的。
ACID要求:①不论是在发生错误时自动进行回滚还是根据需要使用ROLLBACK命令,Oracle都应当为反转未结束的事务而保留原有数据。这种回滚事持久的,而且对所有用户公开;②Oracle数据库必须能够提供一个查询,这个查询结果与该查询开始时的数据库保持一致,此时,如果待查询数据块在该查询开始后发生变化,那么运行这个查询的服务器进程会进入撤销段并构造这些数据块的“读一致”映像。这种回滚是临时的,并且只对于运行这个查询的会话是可视的;③撤销段也用于事务的隔离性,这可能是撤销数据最复杂的用法。隔离性原则要求任何事务都不能以某种方式依赖于其它未结束的事务。即使并发运行若干事务,隔离性也会要求最终结果必须像连续执行这些事务一样。
从9i版本开始,撤销数据也可以用于闪回查询。查询DBA_SEGMENTS,显示下图结果,不过,数据库创建阶段可能不存在撤销表空间。因此,在数据库创建阶段,除数据字典外,Oracle还会在SYSTEM表空间内创建一个过时的回滚段。这回滚段在数据库创建期间使用,但决不会在正常运行期间使用。所有用户事务都将使用撤销段。下图中,做为TYPE2 UNDO段类型列出。
[提示]撤销段的使用与回滚段的使用相矛盾:根据UNDO_MANAGEMENT参数的不同设置,Oracle数据库要么使用撤销段,要么使用回滚段。Oracle Product Development认为TYPE1 UNDO段就是ROLLBACK段。
练习
以用户SYSTEM的身份连接到数据库。
使用如下查询,确定数据库在使用撤销段还是回滚段:
select value from v$parameter where name='undo_management';
这将返回值AUTO。否则,请发出命令,然后重新启动实例:
alter system set undo_management=auto scope =spfile;
使用下面两个查询,确定已经创建的撤销表空间,以及正在使用哪一个:
select tablespace_name from dba_tablespaces wherecontents='UNDO';
select value from v$parameter where name='undo_tablespace';
确定数据库中使用的撤销段及其大小:
select tablespace_name,segment_name,segment_id,status fromdba_rollback_segs;
select usn,rssize from v$rollstat;
注意,段的标识号在两个视图中具有不同的列名。
查看近来数据库中生成的撤销数据量:
alter session set nls_date_format='dd-mm-yy hh24:mi:ss';
select begin_time, end_time,(undoblks * (select value from v$parameter wherename='db_block_size'))
undo_bytes from v$undostat;
2事务的撤销生成方式
在某个事务启动时,Oracle会为其指派一个并且只能指派一个撤销段。任何一个事务都只能受一个撤销段保护,一个事务生成的撤销数据无法被分配到多个撤销段中。因为撤销段的大小可变,所以这并不是问题。如果某个事务填满了自己使用的撤销段,那么Oracle会自动为该撤销段添加另一个区间,从而使这个事务能够继续进行。虽然多个事务可以共享一个撤销段,但是在数据库正常运行时应当不会发生这种情况。撤销管理的一个特性是Oracle会根据需要自动生成新的撤销段,从而能够尽可能的确保多个事务不必共享撤销段。如果Oracle发现有必要扩展撤销段或生成其它撤销段,在工作负荷减少时同样会自动缩小或删除撤销段。
[提示]任何事务生成的撤销数据都无法被分配到多个撤销段中。但一个撤销段可以支持多个事务。在某个事务更新表和索引数据块时,回滚该变化所需的信息会被写入指定撤销段的数据块。所有这些都在数据库高速缓冲区中发生。所有撤销数据一直会被保持至事务被提交。Oracle只能在一定程度上保证一致性,撤销数据被分为不同的必要性级别:“Active”撤销是回滚当前事务可能需要的撤销数据,在事务结束之前,这些数据不能被重写;“Expired”撤销是事务被提交后Oracle不再需要保存的撤销数据。“Unexpired”撤销是中间类型,即非活动也非过期:事务已经提交,但如果任何长时间运行的查询正在进行中,为了读一致性,可能需要撤销数据。
[提示]决不能重写“Active”撤销;可以重写“Expired”撤销。只有在缺少撤销空间的情况下,才能重写“Unexpired”撤销。
可以采用循环方式使用撤销段,或扩展撤销段。Oracle的撤销段自动管理能更好的完成管理任务-与人工管理相比。
与撤销段相关的动态性能视图/数据字典:V$TRANSACTION V$SESSION DBA_ROLLBACK_SEGS V$ROLLSTAT 。
[提示]撤销段与回滚段有所不同,但DBA_ROLLBACK_SEGS和V$ROLLSTAT视图包含二者的行,但不存在任何标志指出所属的段类型。命名约定将此区分开来:将自动生成撤销段名称,并加上前缀_SYSSMU。
下图显示的查询用来研究进行中的事务。第一个查询显示当前有两个事务。为JON的事务分配了SEGMENT_ID编号为7的段,当前使用了撤销空间的277个块。SCOTT的事务小的多,受到段2 的保护。第二个查询显示段信息。每个段的大小因此前分配给它们的事务大小而异。DBA_ROLLBACK_SEGS的连接列称为USN。
练习
如何使用撤销数据来提供事务隔离和回滚,来实施闪回查询。使用两个会话并发连接到HR模式。这可以是两个SQL*Plus会话,或两个SQL DEVELOPER会话,也可以是各一个,下表列出了每个会话的实施步骤。
以用户HR的身份,使用一个会话,演示闪回查询的用法。
将时间显示格式调整为将秒包含在内:
alter session set nls_date_format='dd-mm-yy hh24:mi:ss';
查询和记录当前时间:
select sysdate from dual;
删除前面插入的行,并提交删除:
delete from regions where region_id=100;
commit;
像在删除行之前那样查询表
select * from regions as of timestamp to_timestamp('time_from step_2','dd-mm-yy hh24:mi:ss');
系统列出区域100中已删除的行,这些已从撤销段中检索出来,如下图所示。.
3管理撤销
撤销段的一个主要特征是其被自动管理,必须对Oracle管理撤销段进行某些限制。考虑到数据库中动作的种类与数量,需要设置某些实例参数并针对特定目标调整撤销表空间的大小。
3.1与撤销相关的错误条件管理撤销的原则:①存在允许所有事务继续进行的足够撤销空间;②存在保证查询成功的足够撤销数据。如果某个事务耗尽了撤销空间,出现Oracle错误“ORA-30036,unable to extend segment in undo tablespace.”(无法扩展撤销表空间内的撤销段)而失败。导致这个问题的语句会被回滚,但是指定事务的剩余部分会保持不变并不被提交。如果查询遇到自从查询启动以来更改过的块,它将访问撤销段来查找数据的旧版本,在访问撤销段时,如果一部分撤销数据已被重写,则针对一致性读取的查询将失败,并出现ORA-1555:“snapshot too old.(快照过旧)”。
[提示]如果DML语句用尽撤销空间,则将回滚其已成功的部分。事务的其余部分保持完好,且不提交。
3.2用于撤销管理与保证的参数三个初始化参数控制撤销:UNDO_MANAGEMENT(静态)、UNDO_TABLESPACE(动态)及UNDO_RETENTION(动态)。
在11g版本中,UNDO_MANAGEMENT参数默认为AUTO,也可以将其设置为MANUAL,这时Oracle不会使用撤销段,这样做为了实现向后兼容性。Oracle强烈建议将该参数设置为AUTO,从而启用撤销段的使用。UNDO_MANAGEMENT参数是静态的,改变后只有重新启动实例后才会生效。如果指定UNDO_MANAGEMENT=AUTO,就必须指定UNDO_TABLESPACE参数。UNDO_RETENTION参数通常是可选的,指定了保留非活动撤销数据的目标,并确定合适将其归类为过期。例如,如果运行时间最长的查询需要耗时30分钟,就应当将参数设置为1800。UNDO_RETENTION参数的最大值总是与撤销表空间的大小一致。
[提示]某些查询的运行时间确实很长。持续数天的查询也是存在的,如果希望在正常的事务处理期间成功的运行这种查询,那么就需要一个庞大的撤销表空间。在长时间报告运行期间,我们需要考虑限制DML工作负荷。
从命令行撤销管理
3.3调整与监视撤销表空间在更高级的环境中,最好还应当添加允许闪回查询的空间。查询V$UNDOSTAT视图可以得到需要知道的所有信息,能提供相关信息的还有Database Control内的一个顾问程序,下图显示了Database Control的撤销管理界面。当前使用的撤销表空间称为UNDO1,大小为100M,空间的数据文件可以自动扩展。但Oracle不会仅仅为了实现撤销保留目的而对这些数据文件进行扩展,因此查询可能失败,显示“snapshot too old”。所以不应当依赖自动扩展性能,撤销表空间在最开始时就应当具有正确的大小。
下图中表明,生成撤销的峰值速率仅为每分钟1664KB,而运行时间最长的查询是25分钟。所以要杜绝错误的发生,撤销表空间的最小大小(KB)应为:1664*25=40265。
3.4闪回查询可以使用多种方法来执行闪回查询,最简单使用带有AS OF子句的SELECT语句,例如:select * from scott.emp as of timestamp (systimestamp - 1/1440);--返回十分钟前SCOTT.EMP表中的所有行。
这时可以看到已经删除的行,却看不到已经插入的行,而对于已经更新的行,则只能看到旧值。无论DML语句是否已经提交,情况都是如此。为执行闪回查询,将使用撤销数据来回滚所有更改:已经删除的行从撤销段中提取,再插入结果集,而已经插入的行则从结果集中删除。
下图的语句试图查看一天前的表:
select * from scott.emp as of timestamp (systimestamp - 1);
这条语句很可能失败,并出现“快照过旧”错误,失败原因是,重建表的旧版本所需的撤销数据是整整一天前的事了,而这些肯定已经被重写。
闪回查询可以纠正一些错误,例如,如果由于某些错误,在最近一个小时的某一时刻执行了错误删除(已提交),那么使用下面的命令,会将所有已删除的行插回表中来进行恢复:
insert into scott.emp (select from * scott.emp as of timestamp (systimestamp �C 1/24) minus select * from scott.emp);
如果使用闪回,则必须对撤销系统进行配置,以便通过将UNDO_RETENTION参数设置为适当的值来处理闪回。如果要闪回到一天之前,则必须将其设置为86400秒。必须适当调整撤销表空间的大小。为了确保成功,请启用针对撤销表空间的数据文件的自动扩展,或启用针对表空间的保留保证。[提示]可以使用多种方法来纠正用户错误。最彻底的方法是“不完整恢复”,这将数据库返回到发生错误前的状态,但将丢失随后完成的所有工作,而且占用很长的时间。“数据库闪回”具有相同的效果,但速度快的多。闪回查询通常是最佳的解决方案,但要快一些,否则撤销数据将过期。