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 where contents='UNDO';
select value from v$parameter where name='undo_tablespace';
确定数据库中使用的撤销段及其大小:
select tablespace_name,segment_name,segment_id,status from dba_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 where name='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内的一个顾问程序 , 下图显示了 Data base 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 – 1/24) minus select * from scott.emp);
如 果使用闪回,则必须对撤销系统进行配置,以便通过将UNDO_RETENTION参数设置为适当的值来处理闪回。如果要闪回到一天之前,则必须将其设置为 86400秒。必须适当调整撤销表空间的大小。为了确保成功,请启用针对撤销表空间的数据文件的自动扩展,或启用针对表空间的保留保证。
[提示]可以使用多种方法来纠正用户错误。最彻底的方法是“不完整恢复”,这将数据库返回到发生错误前的状态,但将丢失随后完成的所有工作,而且占用很长的时间。“数据库闪回”具有相同的效果,但速度快的多。闪回查询通常是最佳的解决方案,但要快一些,否则撤销数据将过期。
[提 示]必 须计算出时间最长的查询的耗时。查看V$UNDOSTAT视图的MAXQUERYLEN列具有帮助作用。将UNDO_RETENTION参数设置为大于等 于此值。此后,将撤销表空间的数据文件设置为自动扩展,并启用表空间的RETENTION GUARANTEE。但注意,这可增加填满磁盘空间的可能性,从而产生灾难性的结果。必须对这种状况予以监视。
3.5创建和管理撤销表空间
就数据文件管理,撤销表空间与其它任何表空间没什么不同。但无法指定任何有关存储的选项:无法指定自动段空间管理,无法指定统一的区间大小。创建撤销表空间,适用关键字UNDO:
CREATE UNDO TABLESPACE tablespace_name DATAFILE datafile_name SIZE size
[ RETENTION NOGUARANTEE | GUARANTEE ] ;
默认方式下,此表空间并不确保撤销保留。可以在创建表空间时制定特型,也可以在后期设置:
ALTER TABLESPACE tablespace_name retention [ GUARANTEE | NOGUARANTEE ] ;
[提示]如果创建时不在datafile子句中指定自动扩展特型,那么,撤销表空间的数据文件不会被设置为自动扩展。但是,如果使用DBCA创建了数据库,则将启用撤销表空间的自动扩展(使用无限制的最大大小)。与任何数据文件一样,可以随时启用或禁用自动扩展。
除了自动创建的撤销段之外,无法在撤销表空间中创建段。开始时,将有在撤销表空间中创建的10个撤销段组成的池,如果并发事务超过10个,将创建更多的段。Oracle将监视并发事务率,并根据需要调整段数。
一 般情况下,无论数据库中有多少个撤销表空间,每次都仅使用一个。此表空间中的撤销段将处于"联机"状态(表示可供使用),而其它任何表空间中的段将处于" 脱机"状态,表示不使用他们。如果更改撤销表空间,那么,旧撤销表空间中所有撤销段将脱机,而新撤销表空间中的所有撤销段将联机,以下两种情况例外:
在RAC数据库中,打开数据库的每个实例都必须有自己的撤消表空间。可以针对每个实例将UNDO_TABLESPACE参数设置为不同值来加以来加以控制。每个实例都使相应的撤消段联机。
如果通过更改UNDO_TABLESPACE参数来更改撤消表空间,那么,在事务完成前,任何以前指定的在更改时支持事务的表空间中的段一直处于联机状态。
3.6练习
本练习将使用Database Control创建撤销表空间,然后使用SQL*Plus验证配置。
1. 使用 Database Control,以用户 SYSTEM的身份连接到实例。
2. 在Server选项卡的Storage区域,单击Tab勒索怕侧链接。
3. 单击Create。
4. 输入UNDO2做为表空间名,设置Locally Managed、Undo、 and Read Write对应的单选按钮。
5. 在屏幕底部,单击Add指定数据文件。
6. 输入UNDO2-01.DBF做为文件名,其余的保留默认设置,然后单击Continue。
7. 在Create Tablespace窗口中单击Show SQL, 并研究用于创建撤销表空间的语句。单击Return按钮返回到Create
Tablespace窗口,然后单击OK按钮创建表空间。
8. 使用SQL*Plus,以用户 SYSTEM的身份连接到实例。
9. 运行查询,这个查询将针对数据库中每个表空间返回一行:
select tablespace_name,contents,retention from dba_tablespaces;
可以看到:新创建表空间的内容为UNDO(意味着这个表空间只能用于撤销段),retention为 NOGUARANTEE状态。
10. 运行此查询,它将针对数据库中的每个回滚段或撤销段返回一行:
select tablespace_name, segment_name, status from dba_rollback_segs;
注意,已经在新的撤销表空间中自动创建了多个撤销段,但它们均处于脱机状态。
11. 对实例进行调整,以便使用新的撤销表空间。使用SCOPE子句确保更改永久保存:
alter system set undo_tablespace=undo2 scope=memory;
12. 重新运行步骤(9)的查询。此时将看到,新表空间中的撤销段已重新联机,而此前的活动撤销表空间处于脱机状态。
4小结
Oracle数据库通过使用撤销段,来实现事务原子性、隔离性和读一致性。较早的回滚段仍能使用,在创建数据库时,始终存在一个回滚段。
在撤销表空间中自动创建撤销段,此表空间中不包含其它任何对象。数据库根据需要创建撤销段,试图使段数目与并发事务数目匹配起来。每个段都根据需要自动扩展,以便满足事务的要求。DBA必须确保撤销表空间足够大,可以支持预期的工作负载。
默 认方式下,自动撤销管理机制会优先于查询考虑事务。如果撤销表空间过小,即使必须重写未过期的撤销,也会将事务继续下去,从而面临着"snapshot too old(快照过旧)"错误的查询失败风险。可以修改此行为,以便确保查询能够成功完成,不过这会面临着使事务失败的风险。
只需通过Database Control撤销顾问,或通过查询试图V$UNDOSTAT,即可监视撤销使用情况。