UNDO管理之一:自动UNDO管理
本文主要是对UNDO管理中的一些概念进行强调说明,以及整理了一些UNDO管理中常用的数据字典等等做出详细的介绍。本文不会对UNDO的一些基本概念做详尽的介绍,如果你对于UNDO机制了解的还是不是很清楚的话请先阅读Oracle Concepts, Chapter 9 Data Concurrency and Consistency和Oracle Administrator’s Guide, Chapter 15 Managing Undo以及Oracle9i&10g编程艺术:深入数据库体系结构,第9章 redo与undo。
top实验版本
Oracle数据库版本:
SQL> SELECT * FROM V$VERSION; BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production PL/SQL Release 11.1.0.7.0 - Production CORE 11.1.0.7.0 Production TNS for Linux: Version 11.1.0.7.0 - Production NLSRTL Version 11.1.0.7.0 - Production
操作系统版本:
SQL> !uname -a Linux orainst.desktop.mycompany.com 2.6.18-164.el5 #1 SMP Tue Aug 18 15:51:48 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux
topUNDO基础
topUNDO的作用
UNDO是Oracle中的一个很重要的机制,在对数据库进行修改的时候,Oracle会将数据块上修改之前的数据(称为前映像,before image)保存在回滚段中,这样当我们需要进行回滚(rollback)的时候就很容易能从回滚段中将之前的数据取出来将数据块上面的数据还原回来。
当然上面所说的只是UNDO的最基本的一个用途,实际上UNDO的应用远不止于此,下面就列举一下UNDO的各种作用(对于11gR2版本,不同版本会有些功能差异):
- 数据回滚(rollback)
- 最基本的功能,回滚不需要的操作。
- 数据库恢复(data recovery)
- 在数据库意外宕机之后需要使用UNDO数据进行回滚操作。
- 一致性读(read consistency)
- 提供数据库的一致性读功能,这是一个非常重要的特性。
- 闪回功能(Flashback)
- 除Flashback Database之外其它的闪回都是通过UNDO实现的,包括Flashback Query, Flashback Drop等等。
说到UNDO保存的是数据库中被修改数据的前映像时有人可能会认为Oracle会在数据发生修改的时候将整个数据块复制到回滚段中,然后在回滚的时候再拷贝回来。而实际上不是这样的,这里所说的前映像只是数据的前映像,而不是数据块的,这个要明确。一个数据块在发生回滚之后与修改之前并不会是在物理上一样,只能说是逻辑上一样。要证明这点的最直接的方法也许就是将UNDO块的内容转储(dump)出来看看,但是阅读转储数据是个累人的活儿,实际上我们还是可以通过其它的方法来进行验证的。在讲完下一小节的“UNDO的操作级别”后会给出验证的方法。
topUNDO的产生级别
理解UNDO产生级别对于理解UNDO什么时候产生,UNDO的产生量以及UNDO空间什么时候可以回收等等这些问题非常的重要。
其实所谓的UNDO的产生级别就是UNDO是由什么产生的。UNDO的最基本的作用就是回滚了,而回滚所针对的是事务(transaction),也就是说UNDO是由事务产生的,或者说UNDO的产生级别是事务。在自动UNDO管理的模式下,当开启一个事务修改数据时,Oracle会给这个开启的事务分配回滚段用于存储被修改数据的前映像,在事务回滚或者是提交之前,这些分配的回滚区(一个回滚段可以分配给多个事务,因此回滚数据的状态定义在区(extent)而非段(segment)上)的状态称为活动状态(ACTIVE),处于活动状态的的回滚区对数据的回滚有着至关重要的作用,因此是不能够被覆盖或者是离线(offline)的。如果存在处于活动状态的回滚段丢失(通常是UNDO表空间损坏),这时的未完成事务将因为无法回滚而造成数据的不一致。当这个事务提交或者是回滚之后,所对应的回滚区则标记为非活动(Inactive)状态,处于非活动状态的回滚区不再为数据回滚或是数据库恢复等功能所用,但是UNDO的其它诸如一致性读和闪回等功能却还是有可能用到这些回滚段。因此处于Inactive的回滚区也并不意味着就可以马上丢弃,这个需要取决于UNDO的RETENTION的设置。
注:从术语上说,当使用手工UNDO管理时,所创建的用来存储UNDO数据的数据段称为回滚段(rollback segment),而使用自动UNDO管理时由Oracle自己在UNDO表空间中所创建的存储UNDO数据的数据段则称为撤销段(undo segment),不过在文中为了方便都统一的称为回滚段。
在动态视图V$TRANSACTION中,有几个字段就为我们提供了关于那些正在进行的事务所对应的UNDO段的相关信息:
- 事务所使用的UNDO段信息
-
- XIDUSN NUMBER Undo segment number
- PRV_XIDUSN NUMBER Previous transaction undo segment number
- 事务UNDO空间使用情况
-
- USED_UBLK NUMBER Number of undo blocks used
- USED_UREC NUMBER Number of undo records used
- 事务当前UBA(UNDO块地址)信息
-
- UBAFIL NUMBER Undo block address (UBA) filenum
- UBABLK NUMBER UBA block number
- UBASQN NUMBER UBA sequence number
- UBAREC NUMBER UBA record number
- 事务起始UBA信息
-
- START_UBAFIL NUMBER Start UBA file number
- START_UBABLK NUMBER Start UBA block number
- START_UBASQN NUMBER Start UBA sequence number
- START_UBAREC NUMBER Start UBA record number
下面显示的就是一个事务的UNDO信息:
SQL> UPDATE tt0 SET a=1 WHERE a=1; 1 row updated. SQL> SELECT XID AS "txn id", XIDUSN AS "undo seg", USED_UBLK "used undo blocks", 2 XIDSLOT AS "slot", XIDSQN AS "seq", STATUS AS "txn status" 3 FROM V$TRANSACTION; txn id undo seg used undo blocks slot seq txn status ---------------- ---------- ---------------- ---------- ---------- ---------------- 05001E00AD0A0000 5 1 30 2733 ACTIVE
现在回到上一小节所说的UNDO是否保存的是被修改的数据库的前映像的问题,V$TRANSACTION中的USED_UBLK字段可以帮我们澄清这个问题:如果UNDO保存的数据块的前映像的话,如果我们修改两个数据快,那USED_UBLK将会是两个,而非一个。下面就来验证一下。
首先我们找出处于两个不同块上的列A的值。
SQL> SELECT MAX(a),DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)
2 FROM tt0 GROUP BY DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)
3 ORDER BY 1;
MAX(A) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
---------- ------------------------------------
657 21091
1314 21092
1971 21093
3 rows selected.
上面可以看到列A值657和1314分别位于块21091和21092上,现在我们修改这两个值,再看看此时的USED_UBLK会是多少。
SQL> rollback; Rollback complete. SQL> UPDATE tt0 SET a=657 WHERE a=657; 1 row updated. SQL> UPDATE tt0 SET a=1314 WHERE a=1314; 1 row updated. SQL> SELECT XID AS "txn id", XIDUSN AS "undo seg", USED_UBLK "used undo blocks", 2 XIDSLOT AS "slot", XIDSQN AS "seq", STATUS AS "txn status" 3 FROM V$TRANSACTION; txn id undo seg used undo blocks slot seq txn status ---------------- ---------- ---------------- ---------- ---------- ---------------- 2D000A0006000000 45 1 10 6 ACTIVE
从结果可以看到,USED_UBLK是1,而不是2,这就从侧面说明了UNDO保存的是数据的前映像而非数据块的前映像。
当然,有个事务信息,我们就可以找到对应的会话相关信息,这也就是我们分析当前正在进行事务UNDO使用情况的一个方法,这个后面会说到。
topUNDO管理方法
topUNDO管理方法的演化
- 9i之前的版本
- 手工UNDO管理,DBA要手工创建UNDO段提供给UNDO使用,比较麻烦。
- 9i
- 引入自动UNDO管理,Oracle可以利用现有的UNDO表空间自动进行UNDO信息和空间的管理,然后通过指定UNDO RETENTION来决定非活动UNDO信息的保留期限。
- 10g
- 引入自动RETENTION优化,可以根据UNDO表空间的大小以及自动增长的情况自动的优化UNDO RETENTION,最大限度的利用UNDO空间来避免ORA-1555之类的错误产生。
- 11g
- 数据库在创建的时候默认使用自动UNDO管理。
top自动UNDO管理
自动UNDO管理(Automatic UNDO Management, AUM)是Oracle从9i开始推出的新UNDO管理方式,之前的UNDO管理都是靠手工创建UNDO段来完成的。有了AUM之后,Oracle可以在UNDO表空间当中自动的管理UNDO信息和UNDO所占用的空间,在无需人工参与空间分配等活。
与AUM相关的两个最基本的参数就是UNDO_MANAGEMENT和UNDO_TABLESPACE。
- UNDO_MANAGEMENT
- 决定了使用自动(AUTO)还是手动(MANUAL)的UNDO管理方式,从11g开始默认情况下是使用自动UNDO管理,Oracle自身也是推荐使用AUM。
- UNDO_TABLESPACE
- 指定了Oracle该在那个UNDO表空间中创建自动管理的UNDO段。UNDO_TABLESPACE的选择方法如下:
- 如果系统中不存在UNDO表空间,则数据库打开时自动选用使用SYSTEM表空间。
- 如果系统中存在多个UNDO表空间,默认情况下数据库打开时使用第一个可用的UNDO表空间。
- 在系统运行中如果不设置UNDO_TABLESPACE,则事务将无法执行。
top自动UNDO管理的RETENTION
前面说过,在使用AUM的时候,在一个事务提交或者是回滚之后,该事务所对应的UNDO数据将不再为事务或者是数据库恢复所需要,但是考虑到读数据一致性和Flashback特性的需要,我们还需要将这些UNDO数据保留一段时间,这段时间被称为UNDO RETENTION。现在我们可以再继续介绍回滚区的状态了,同样上面说到回滚或者是提交之后的回滚区将是非活动状态,然而这种非活动状态还是可以继续细分的。那些还处于UNDO RETENTION之内的回滚区的状态为未过期(UNEXPIRED),而处于UNDO RETENTION之外的回滚区则称为已过期(EXPIRED),未过期的回滚区不会轻易的被覆盖,稍后会说到未过期的回滚区的使用原则;而已过期的回滚区则随时有可能为新的事务所重复利用。
特别要注意的一点就是一般情况下所说的UNDO RETENTION都是一个期望(Expected),而非保证(Guaranteed)。现在假设一个情形:数据库所使用的UNDO表空间的数据文件设置为非自动扩展,现在UNDO表空间中同时存在有活动、未过期、已过期、未使用等4种回滚区。当进行一个大的事务的时候,该事务会优先使用已过期回滚区和未使用空间,但是当事务用完这些可用空间之后发现还是不够那怎么办呢?这时候事务会继续使用那些状态为未过期的回滚区,使用顺序是从使用时间越早的开始,这时候Oracle是不会再顾及UNDO RETENTION设置的,保证事务正常运行最重要。这也就是UNDO RETENTION只能是一个期望而非保证的原因。你也许会问如果未过期的回滚区也用完了之后会怎么样呢?活动的回滚区是不可能重用的,因此事务报个错然后会死掉的。当然如果UNDO表空间是自动扩展的话Oracle就是先保证UNDO RETENTION而去扩展数据文件了。
当然,Oracle从10g开始也是提供了GUARANTEED UNDO RETENTION选项的,要使用GUARANTEED UNDO RETENTION则需要设置UNDO表空间的RETENTION GUARANTEE属性,下面就是使用的例子:
-- 创建新的UNDO表空间的时候指定RETENTION GUARANTEE属性 SQL> CREATE UNDO TABLESPACE undo_t2 2 DATAFILE '/data/undo-t2.dbf' SIZE 100M 3 RETENTION GUARANTEE; Tablespace created. -- 修改现有UNDO表空间的RETENTION GUARANTEE属性 SQL> ALTER TABLESPACE undo_t2 RETENTION GUARANTEE; Tablespace altered. -- 取消现有UNDO表空间的RETENTION GUARANTEE属性 SQL> ALTER TABLESPACE undo_t2 RETENTION NOGUARANTEE; Tablespace altered.
使用GUARANTEED UNDO RETENTION之后,未过期的UNDO数据将不会再被覆盖掉。不过这是一个很危险的举措,因为这个一不小心就是造成事务失败。在没有百分百使用的理由支持之下是不要去做的。
topUNDO数据状态与UNDO自动调优
前面说了半天的UNDO数据状态,问题是这些状态从哪里可以看到呢?答案就是在DBA_UNDO_EXTENTS中,DBA_UNDO_EXTENTS中存储了所有分配的UNDO区信息,其中的STATUS显示的就是每个分配的区当前的状态,分为ACTIVE, UNEXPIRED和EXPIRED三种。
下面是一个DBA_UNDO_EXTENTS的查询结果示例:
-- 开启一个活动的事务 SQL> UPDATE TT SET A=1 WHERE A=1; 1 row updated. -- 看看UNDO数据的状态 SQL> SET LINES 145 PAGES 9999 SQL> COL SEGMENT_NAME FOR A25 SQL> COL TABLESPACE_NAME FOR A10 SQL> SELECT SEGMENT_NAME,TABLESPACE_NAME,EXTENT_ID,STATUS 2 FROM DBA_UNDO_EXTENTS 3 WHERE SEGMENT_NAME='_SYSSMU143_1273636148$' OR STATUS='ACTIVE'; SEGMENT_NAME TABLESPACE EXTENT_ID STATUS ------------------------- ---------- ---------- --------- _SYSSMU147_1273636148$ UNDO_T2 0 ACTIVE _SYSSMU143_1273636148$ UNDO_T2 0 UNEXPIRED _SYSSMU143_1273636148$ UNDO_T2 1 EXPIRED
现在看看我这里相关参数的设置:
SQL> SHOW PARAMETER UNDO NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ undo_management string AUTO undo_retention integer 60 undo_tablespace string UNDO_T2
我这里的RETENTION为60秒,现在将上面的那个事务提交,等待一分钟之后再去查看UNDO数据的状态看看:
SQL> SELECT SEGMENT_NAME,TABLESPACE_NAME,EXTENT_ID,STATUS 2 FROM DBA_UNDO_EXTENTS 3 WHERE SEGMENT_NAME='_SYSSMU147_1273636148$' OR STATUS='ACTIVE'; SEGMENT_NAME TABLESPACE EXTENT_ID STATUS ------------------------- ---------- ---------- --------- _SYSSMU147_1273636148$ UNDO_T2 0 UNEXPIRED _SYSSMU147_1273636148$ UNDO_T2 1 EXPIRED
现在你应该发现第一行数据并没有变成EXPIRED,依然保持着UNEXPIRED的状态,尽管RETENTION设置只有60秒,为什么呢?回答了这个问题也就回答了为什么UNDO表空间会一直保持将近100%使用率的问题。
要回答这个问题就要说到UNDO的自动优化功能了,从10g开始,Oracle提供了UNDO自动优化功能,所谓的UNDO自动优化就是在UNDO表空间非自动增长的情况下,Oracle会根据UNDO表空间的大小来调整UNDO RETENTION的大小,自动调整RETENTION就是最大限度的利用当前UNDO表空间的可用空间,尽可能的保留最多的UNDO数据,以最大化的减少类似ORA-1555之类的错误发生。在这种情况下的UNDO RETENTION设置只是一个摆设,属于基本无用的了。
经过自动优化后的UNDO RETENTION可以在动态视图V$UNDOSTAT.TUNED_UNDORETENTION中看到。默认情况下,Oracle会每10分钟往V$UNDOSTAT中插入一条当前UNDO表空间使用情况的数据,其中就包含了当时自动优化后的UNDO RETENTION数值。现在就来看看这个动态视图的数据:
SQL> ALTER SESSION SET NLS_DATE_FORMAT='YYYY/MM/DD HH24:MI:SS' ;
Session altered.
SQL> SELECT begin_time, end_time, tuned_undoretention FROM v$undostat;
BEGIN_TIME END_TIME TUNED_UNDORETENTION
------------------- ------------------- -------------------
2010/05/12 08:32:51 2010/05/12 08:41:05 249606
2010/05/12 08:22:51 2010/05/12 08:32:51 243920
... 中间省略部分数据 ...
29 rows selected.
SQL> select 249606/3600 Hours from dual;
HOURS
----------
69.335
很明显的可以看到,自动优化后的UNDO RETENTION是69小时多,从这个看我们上面看到的DBA_UNDO_EXTENTS.STATUS为UNEXPIRED就很正常了。
UNDO自动优化功能的出发点是很好的,但是也带来一个问题:在跑完一个大事务之后发现UNDO表空间会在很长时间都一直保持着使用率是接近100%的状态,这是一个很让人的郁闷的事情,这种接近100%的状态还无法手工的收缩,甚至于重启数据库实例也无法缓解,而此时你的表空间的监控报警会常常给你发报警的。考虑到这种种的问题,DBA禁用UNDO自动优化功能也是很正常的了。只是Oracle所提供的禁用UNDO自动优化的参数竟然是个隐含参数,名叫”_undo_autotune”,看来Oracle对自己的UNDO自动优化还是比较有信心的,只是没有想到大家会因为空间问题而不喜欢它。禁用方法如下:
SQL> ALTER SYSTEM SET "_undo_autotune"=FALSE; System altered. SQL> SHOW PARAMETER "_undo_autotune" NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ _undo_autotune boolean FALSE
禁用UNDO自动优化之后,Oracle不再勤奋的每十分钟记录一次当前UNDO使用情况了,在动态视图V$UNDOSTAT中也只有一条数据:
SQL> SELECT begin_time, end_time, tuned_undoretention FROM v$undostat; BEGIN_TIME END_TIME TUNED_UNDORETENTION ------------------- ------------------- ------------------- 2010/05/12 08:57:40 2010/05/12 09:02:48 0
top延伸阅读
- V$TRANSACTION @ 11gR2 Oracle Database Reference
- V$ROLLSTAT @ 11gR2 Oracle Database Reference
- V$UNDOSTAT @ 11gR2 Oracle Database Reference
- Undo Segments @ 11gR2 Concepts
- Oracle9i&10g编程艺术:深入数据库体系结构
作者:马齿苋 | 链接:http://www.dbabeta.com/2010/undo-management_auto-undo-management.html
flashback drop:recyclebin
很不错的文章,收获不小