ORA-01555是Oracle数据库运行过程中常见的一个错误。以下就是Oracle关于ORA-01555错误的经典描述:
ORA-01555: snapshot too old (rollback segment too small)
Cause: rollback records needed by a reader for consistent read are
overwritten by other writers
简单而言,就是为保证一致性读的回退段数据被其它写进程所覆盖了。以下就是一个典型例子:
ORA-01555错误的原因和解决方案比较复杂,Oracle有关该错误处理的文章也比较多。本书我们一方面主要针对9i之后的自动UNDO管理技术(Automatic UNDO Management),另一方面也只针对普通表的ORA-01555错误处理,而不关注LOB等特殊对象的ORA-01555错误处理。
首先,分别从应用会话窗口和alert.log中分别获取相关信息。
例如,应用会话窗口显示错误信息:
ORA-01555: snapshot too old: rollback segment number 9 with name “_SYSSMU1$” too small
Alert.log中显示:
ORA-01555 caused by SQL statement below (Query Duration=9999 sec, SCN:0x000.008a7c2d)
其次,通过alert.log确定QUERY DURATION。上例中为9999秒。
第三,从应用会话信息中确定undo segment名称。例如:_SYSSMU1$。
最后,确定UNDO表空间的UNDO_RETENTION值。
SQL> show parameter undo_retention
此时,Oracle无法保证当提交的事务过期,也就是超过UNDO_RETENTION时间之后,还能确保数据的一致性读取。
这种情况下,最有效的解决办法是优化查询语句,降低语句的QUERY DURATION时间。如果无法优化了,则只能参考QUERY DURATION时间值来扩大UNDO_RETENTION值,确保Oracle保存更长时间的UNDO信息。
扩大UNDO_RETENTION值,意味着需要更多的UNDO表空间,下面还将介绍UNDO表空间的计算方法。
在这种情况下,通常而言是UNDO表空间满了。如何进一步确定UNDO表空间是否满了呢?执行如下脚本:
set pagesize 25
set linesize 120
select inst_id,
to_char(begin_time,’MM/DD/YYYY HH24:MI’) begin_time,
UNXPSTEALCNT “# Unexpired|Stolen”,
EXPSTEALCNT “# Expired|Reused”,
SSOLDERRCNT “ORA-1555|Error”,
NOSPACEERRCNT “Out-Of-space|Error”,
MAXQUERYLEN “Max Query|Length”
from gv$undostat
where begin_time between
to_date(‘<start time of the ORA-1555 query>’,’MM/DD/YYYY HH24:MI:SS’)
and
to_date(‘<time when ORA-1555 occured>’,’MM/DD/YYYY HH24:MI:SS’)
order by inst_id, begin_time;
其中:
Tue May 26 16:16:57 2009
ORA-01555 caused by SQL statement below (SQL ID: 54yn3n36w24ft, Query Duration=922 sec, SCN: 0x0007.8a55f4e3)
922秒为15分22秒。这样 ORA-1555开始发生的时间为 May 26 16:01:35 2009(16:01:35 = 16:16:57 – 15:22)。
UNDO表空间的计算公式如下:
UndoSpace = UR * (UPS * DBS)
其中:
上述UNDO_RETENTION、DB_BLOCK_SIZE可通过初始化参数文件获取,而UPS则可以通过查询v$undostat视图而获得。Oracle建议查询业务高峰时段产生的UNDO数据块数量。为此,执行如下查询:
SELECT undoblks / ((end_time – begin_time) * 86400) “Peak Undo Block Generation”
FROM v$undostat
WHERE undoblks = (SELECT MAX(undoblks) FROM v$undostat);
最终,计算高峰时段所需UNDO表空间大小的语句如下:
SELECT (UR * (UPS * DBS)) AS “Bytes”
FROM (SELECT value AS UR FROM v$parameter WHERE name = ‘undo_retention’),
(SELECT undoblks / ((end_time – begin_time) * 86400) AS UPS
FROM v$undostat
WHERE undoblks = (SELECT MAX(undoblks) FROM v$undostat)),
(SELECT block_size AS DBS
FROM dba_tablespaces
WHERE tablespace_name =
(SELECT UPPER(value)
FROM v$parameter
WHERE name = ‘undo_tablespace’));
ORA-30036也是Oracle数据库运行过程中常见的一个错误。以下就是Oracle关于ORA-30036错误的经典描述:
Error: ORA-30036 (ORA-30036)
Text: unable to extend segment by %s in undo tablespace ‘%s’
—————————————————————————
Cause: the specified undo tablespace has no more space available.
Action: Add more space to the undo tablespace before retrying the operation. An alternative is to wait until active transactions to commit.
该错误表示就是UNDO表空间不够了,简单解决办法就是对UNDO表空间进行扩容。但如同Oracle其它空间不够的类似错误一样,扩容并非唯一解决办法。
欲深入了解ORA-30036错误原因和解决办法,其实应从深入了解UNDO表空间分配算法开始。以下就是该算法主要思路:
select sum(bytes) from dba_free_space where tablespace_name=’UNDOTBS1′;
select sum(bytes) from dba_data_files where tablespace_name=’UNDOTBS1′;
select autoextensible from dba_data_files where tablespace_name=’UNDOTBS1′;
SELECT DISTINCT STATUS, SUM(BYTES), COUNT(*) FROM DBA_UNDO_EXTENTS GROUP BY STATUS;
如果没有过期(expired)而只有非过期(unexpired)的Undo Extent,以及Active Extents,则Undo表空间的确太小,需要对Undo表空间大小进行重新规划并扩容。关于Undo表空间大小的计算方法,请见本章前述内容。在10g中还可以通过OEM中的Undo Advisor特性来进行Undo表空间的规划。
假设Undo表空间不够,则Oracle会尝试偷取非过期(unexpired)的Undo Extent,此时可能会导致ORA-1555错误。如果也没有非过期(unexpired)的Undo Extent,则的确需要对Undo表空间进行扩容。
10g中可以为Undo表空间指定Guaranteed Undo Retention特性。例如:
create undo tablespace undotbs1 datafile ‘undotbs1.dbf’size 1000M autoextend on
retention guarantee;
这样,Oracle就不会重复使用非过期(unexpired)的Undo Extent。因此,此时只能对Undo表空间扩容了。
如果有过期(expired)的Undo Extent,意味着这些extent是可以被重用的。但系统却报出ORA-30036,则很有可能是撞上Oracle Bug 5442919了。以下就是满足该Bug的所有条件:
select count(*) from dba_rollback_segs where status=’OFFLINE’;
select sum(bytes) “UNEXPIRED BYTES” from dba_undo_extents where tablespace_name=’UNDOTBS1’and status=’UNEXPIRED’;
select sum(bytes) “EXPIRED BYTES” from dba_undo_extents where tablespace_name=’UNDOTBS1’and status=’EXPIRED’;
该Bug在10.2.0.4以及11g中就已经修复了。在之前的版本,例如9i和10.2.0.1/2/3中,在某些平台可以向Oracle服务部门申请补丁回退(Backport),但这些版本早已经过了Oracle产品服务期,估计已经很难得到Oracle服务部门支持了。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31401608/viewspace-2149365/ ,如需转载,请注明出处,否则将追究法律责任。