在Oracle 10.2.0.1.0中,只要设置了undo表空间自动管理,不管有没开启自动扩展,不管undo_retention设置为多少,都会启用 Automatic Tuning of undoretention的新特性。这个新特性中计算RETENTION算法有问题,会导致unexpired undo数据奇高,并最终导致出现ORA-1628: max # extents 32765reached for rollback segment错误。
1 问题现象
Oracle版本:10.2.0.1.0。
浙江现场NQA在执行update/insert操作失败,ORACLE返回ORA-1628错误,并且ORACLE的alert日志中ORA-1628出现的非常频繁。错误日志:
Update fail,msg::ORA-01628: max # extents (32765) reached for rollback segment _SYSSMU7$
2 分析
我们在alert日志中发现了ORA-30036错误,出现ORA-30036表示UNDO表空间太小。
ORA-30036的错误描述:
Update fail,msg::ORA-30036: unable to extend segment by 8 in UNDOtablespace 'UNDOTBS1'
事务申请undo空间的流程如下:
1) 事务启动时,ORACLE会为之分配一个undo segment。ORACLE的设计目标是一个事务对应一个undo segment。ORACLE启动时,只使得部分undo segments变为online。随着事务数量的增多,更多的offline UNDOsegments变为online状态。如果所有undo segment已经是online状态,且undo表空间还有足够的空间,oracle会创建新undo segment;如果undo表空间的空间已经用尽,几个事务会合用一个undo segment。
2) 检查事务对应的undo segment是否有空闲区(extent),如果有直接使用。
3) 如果没有,使用本segment中处于expired状态的extent,这些extent存储了由其它事务提交或回滚留下的过期数据。这个动作称为一次扩展(wrap),计入v$rollstat的wraps列。
4) 如果本回滚段中没有可用的区,从UNDO表空间中请求区。这被称为一次Extend,记入v$rollstat的EXTENTS列。
5) UNDO表空间中没有Free区,从其他回滚段Steal过期的区。Steal的单位一定是以区为单位。无论Steal是否成功,V$UNDOSTAT的EXPSTEALCNT列都会加1,此列统计的是次数。EXPBLKRELCNT列是成功Steal的块数。
6) 如果Steal过期区不成功,试图扩展数据文件。
7) 如果无法扩展文件,在本回滚段中重用未过期的区, V$UNDOSTAT.UNXPBLKREUCNT列增加(增加值是区中块的个数)
8) 如本回滚段无过期的块,则Steal其他回滚段中未过期的区。每Steal一次,无论是否成功,都会记入V$UNDOSTAT.UNXPSTEALCNT列。Steal的块数记入NXPBLKREUCNT列。
9) 如还不行,报ORA-30036错误。
于是,创建新的undo 表空间UNDOTBS2,UNDOTBS2包含了4个数据文件,每个文件有31GB。然后切换至新的undo表空间。为什么数据文件大小是31G,在block大小为8K的情况下,数据文件大小限制是32G,有人说数据文件变为32G后会出现bug,为了避免这种情况,于是设置数据文件大小为31G。
【切换undo的表空间的代码如下】
--查看当前的undo表空间
show parameter undo_tablespace;
--查看所有undo表空间
select * from dba_tablespaces where contents='UNDO';
--查看当前undo表空