转载自tangyunoracle
1、什么是undo
当我们对数据执行修改操作时,数据库会生成undo 信息,这样一旦执行的事务或语句由于某种原因失败,或者发出一条ROLLBACK 语句请求回滚,就可以利用这些undo信息将数据放回到修改前的样子。undo 信息存储在一组特殊的段中,这称为undo 段(undo segment)。select segment_name,tablespace_name,status,block_id,file_id from dba_rollback_segs;
2、undo有什么作用
在Oracle数据库中,undo主要有三大作用:提供一致性读(Consistent Read)、回滚事务(Rollback Transaction)以及实例恢复(Instance Recovery)。
2.1、一致性读(Consistent Read)
一致性读是相对于脏读(Dirty Read)而言的。假设某个表T中有10000条记录,获取所有记录需要15分钟时间。当前时间为9点整,某用户A发出一条查询语句:select * from T,该语句在9点15分时执行完毕。当用户A执行该SQL语句到9点10分的时候,另外一个用户B发出了一条delete命令,将T表中的最后一条记录删除并提交了。那么到9点15分时,A用户将返回多少条记录?正确的应该是10000条记录。很明显,在 9点钟那个时间点发出查询语句时,表T中确实有10000条记录,只不过由于I/O的相对较慢,所以才会花15分钟来完成所有记录的检索。
这是因为ORACLE通过构造CR(consistent read)块提供一致读的方式,保证了数据的完整性。具体的实现方式如下:
用户在进行查询时oracle会先记录当时的SCN号,当查询读到被B用户更新删除记录后的块时,发现这个块头部ITL槽中的SCN号比查询开始时的SCN号大,这样就会在回滚段中寻找这个块的前映像数据,找到这个数据的前映像后,把前映像和CURRENT的数据块进行合并,就形成了一个CR BLOCK,通过查询CR BLOCK就可以得到一致性的数据。
2.2、回滚事务(Rollback Transaction)
当用户发出一个update 操作后,会在回滚段中记录更新记录的前映像数据,如果用户再发出rollback命令撤销数据变化时,Oracle利用记录在ITL槽里记录的undo 块的地址找到该undo块,然后从中取出变化前的值,并放入数据块中,从而对事务所作的变化进行回滚。
2.3、实例恢复(Instance Recovery)
实例恢复则是在SMON进程完成前滚并打开数据库以后发生。SMON进程会去查看undo segment头部(所谓头部就是undo segment里的第一个数据块)记录的事务表(每个事务在使用undo块时,首先要在该undo块所在的undo segment的头部记录一个条目,该条目里记录了该事务相关的信息,其中包括是否提交等),将其中既没有提交也没有回滚,而是在实例崩溃时被异常终止的事务全部回滚。
3、回滚段管理方式
oracle的undo管理有两种方式,自动管理和手动管理,可以使用 undo_management 参数来进行控制。当设置为auto时使用undo表空间的方式来自动管理undo段,如果设置为manual则使用rollback segment方式存储undo信息。
oracle9i 以后开始使用undo自动管理,手动管理方式只在特殊的场合下才会偶尔使用到。后面在介绍undo恢复时再做相应介绍。
说到自动管理,首先要介绍UNDO_RETENTION参数,这个参数用来指定undo 记录保存的最长时间,默认为900秒,可以动态的进行修改。这个参数不是指undo中的数据在undo表空间中一定要保存900秒,例如当一个新事务开始的时候,如果发现undo表空间已经被写满,则新事务的数据会自动覆盖已提交事务的数据,而不管这些数据是否已存放够900秒。同时也不是指undo_retention 中指定的时间一过,已经提交事务中的数据就立刻无法访问,通常它只是失效,只要没有被别的事务覆盖,它就会仍然存在,这时我们可以使用flashback 特性查看表在更新前不同时刻的数据。
因此UNDO表空间中的数据在不同时段就会有不同的状态显示,在dba_undo_extents 数据字典里记录了UNDO中每个区段的状态.
SQL> SELECT tablespace_name, status, SUM (bytes) / 1024 / 1024 "Bytes(M)"
FROM dba_undo_extents
GROUP BY tablespace_name, status;
TABLESPACE_NAME STATUS Bytes(M)
---------------- --------- ----------
UNDOTBS2 EXPIRED 1.4375
UNDOTBS2 UNEXPIRED .375
UNDOTBS2 ACTIVE .125
UNDOTBS1 EXPIRED 22
其中:
ACTIVE :未提交的回滚数据,该数据所关联的事务并未提交,用于实现读一致性,所以该数据不能被其它事务的数据所覆盖 。
UNEXPIRED:已经提交但未过期的回滚数据,该数据关联的事务已经提交,但是仍受到undo retention参数保持时间的影响,当undo表空间中没有可用的数据块时,这些数据块会直接被覆盖而进行重用。
EXPIRED: 事务已经提交,而且数据保存时间已经超过undo retention参数指定的时间,属于已经过期的数据.可以被随时重用。
需要说明的是,当设置表空间启动Guarantee特性时,UNEXPIRED类型的块就必须要等到undo_retention 指定时间过期后才能被重用。
4、undo段的常见问题及维护操作
4.1、Oracle ORA-01555 快照太旧
ORA-01555是oracle中常见的一个错误,例如当我们进行的事务需要使用undo数据来构造CR块的时候,如果对应的undo信息已经被覆盖时,就会报出ora-01555错误。
对于这种情况,通常有以下几种解决办法。
1、优化出错的SQL,减少语句的查询时间。
2、增加UNDO表空间大小
3、增加undo_retention 时间,默认只有15分钟
4、避免频繁的提交
4.2、Oracle ORA-1628 回滚段达到32765最大值
undo表空间自动管理方式下,单个回滚段的最大区数为32765,我们知道一个事务只能使用一个回滚段,当一个大事务在进行大量数据更新时,所使用的回滚段不能完全存放这个事务的前映像数据时, 就可能会出现这种情况,这种情况下只能通过切换undo表空间来排除故障。避免这种故障的根本原因还是要优化相应的SQL语句,减少UNDO块的产生。
出现ORA-1628故障时至少会有一个回滚段的状态会显示为FULL,如下表信息:
SQL> select segment_name,max_extents,status from dba_rollback_segs;
SEGMENT_NAME MAX_EXTENTS STATUS
----------------------- ----------- --------
SYSTEM 32765 ONLINE
_SYSSMU1$ 32765 OFFLINE
_SYSSMU2$ 32765 OFFLINE
_SYSSMU3$ 32765 FULL
_SYSSMU4$ 32765 OFFLINE
_SYSSMU5$ 32765 OFFLINE
_SYSSMU6$ 32765 OFFLINE
4.3、UNDO表空间损坏后的数据恢复
如果数据库在运行过程中出现undo表空间故障时,通常可以通过在线新建undo表空间,并且切换为默认表空间后就能快速解决故障。假如undo损坏而且数据库在关闭状态,如果没有任何有效的备份时,可以通过修改undo手动管理的方式来启动数据库。
这里用一个案例来说明恢复的过程。
系统环境: oracle 10.2.0.4 非归档方式,无有效备份
故障现象:
数据库无法启动,alert日志中有大量的ora-600 错误
ORA-00600: internal error code, arguments: [2662], [1], [3008810928], [1], [3008849117], [8388617], [], []
ORA-00600: internal error code, arguments: [4194], [15], [6], [], [], [], [], []
Mon May 23 18:36:46 2011
Doing block recovery for file 2 block 336654
Block recovery from logseq 2200, block 63 to scn 7317545555
故障分析:
根据提示信息,可以查到是undo表空间的数据文件出现坏块造成数据库无法启动,因数据库为非归档方式,没有有效的undo备份文件,这种情况下就可以使用undo手动管理的方式启动数据库,详细可以参考Metalink文章[ID 281429.1] 。
下面是大概的步骤介绍。
1、启动到nomount 状态,备份参数文件
2、修改参数文件,undo_management=manual
3、使用新的参数文件启动数据库
4、创建新的回滚段
SQL> create rollback segment r01;
5、设置回滚段为online
SQL> alter rollback segment r01 online;
6、创建表空间undotbs2
7、停库,修改参数为表空间自动管理,
8、重启启动数据库。
---------------------End-----------------------------------------------------------