共计 6103 个字符,预计需要花费 16 分钟才能阅读完成。
这篇文章给大家分享的是有关 Oracle 中如何解决 ORA-01555 错误的内容。丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,一起跟随丸趣 TV 小编过来看看吧。
11.6 ORA-01555: 快照太旧
什么是 ORA-01555 错误?
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
简单而言,就是为保证一致性读的回退段数据被其它写进程所覆盖了。以下就是一个典型例子:
时间点 1:会话 1 对 A 表开始进行查询操作。
时间点 2:会话 2 修改 A 表的记录 X。
时间点 3:当会话 1 的查询语句查询到记录 X 时,通过 SCN 号发现记录 X 被修改了,而且修改的时间(时间点 2)晚于时间点 1。这样,Oracle 将通过保存在 UNDO 中记录 X 修改前的数据(简称 Before Image),来进行一致性读取。
时间点 4:会话 2 修改 A 表的记录 Y,并且进行了 commit 操作。这样,该事务的 slot 数据就可以被 Oracle 覆盖了。
时间点 5:会话 2 修改 A 表的记录 Z,并且进行了 commit 操作。此时,由于 UNDO 表空间的空间不足,记录 Y 的修改前的数据被 Oracle 覆盖了。
时间点 6:当会话 1 的查询语句查询到记录 Y 时,通过 SCN 号发现记录 Y 被修改了,而且修改的时间(时间点 6)晚于时间点 1。于是,Oracle 将通过保存在 UNDO 中记录 Y 修改前的数据(简称 Before Image),来进行一致性读取。但此时记录 Y 修改前的数据已经在时间点 5 被覆盖了。因此,系统将报 ORA-01555 错误!
ORA-01555 错误的原因和解决方案比较复杂,Oracle 有关该错误处理的文章也比较多。本书我们一方面主要针对 9i 之后的自动 UNDO 管理技术(Automatic UNDO Management),另一方面也只针对普通表的 ORA-01555 错误处理,而不关注 LOB 等特殊对象的 ORA-01555 错误处理。
如何获取 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
如何解决 ORA-01555 错误?
如果 QUERY DURATION UNDO_RETENTION
此时,Oracle 无法保证当提交的事务过期,也就是超过 UNDO_RETENTION 时间之后,还能确保数据的一致性读取。
这种情况下,最有效的解决办法是优化查询语句,降低语句的 QUERY DURATION 时间。如果无法优化了,则只能参考 QUERY DURATION 时间值来扩大 UNDO_RETENTION 值,确保 Oracle 保存更长时间的 UNDO 信息。
扩大 UNDO_RETENTION 值,意味着需要更多的 UNDO 表空间,下面还将介绍 UNDO 表空间的计算方法。
如果 QUERY DURATION = UNDO_RETENTION
在这种情况下,通常而言是 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;
其中:
UNXPSTEALCNT 字段表示提交的 Transaction Slots 没有超出 UNDO_RETENTION 时间,也就是处于 unexpired 状态,但由于 UNDO 表空间满了,而被 Oracle 覆盖了的次数。
start time of the ORA-1555 query 时间可通过 ORA-1555 发生时间减去 QUERY DURATION 而得到。例如:
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 表空间大小?
UNDO 表空间的计算公式如下:
UndoSpace = UR * (UPS * DBS)
其中:
UR = UNDO_RETENTION 参数,单位为秒。
UPS = 每秒产生的 UNDO 数据块数量。
DBS = DB_BLOCK_SIZE 参数。
上述 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’));
11.7 ORA-30036: UNDO 表空间无法扩展
什么叫 ORA-30036 错误?
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 其它空间不够的类似错误一样,扩容并非唯一解决办法。
UNDO 表空间分配算法
欲深入了解 ORA-30036 错误原因和解决办法,其实应从深入了解 UNDO 表空间分配算法开始。以下就是该算法主要思路:
如果当前的 UNDO extent 还有空间,则从中分配新的数据块。
否则,假设下一个 extent 过期(expired)了,则跳到(wrap)下一个 extent,并且返回其第一个数据块。
假设下一个 extent 为非过期(unexpired)的,则尝试从 UNDO 表空间分配新的空间。假设 UNDO 表空间足够,则分配新的 extent 给 Undo segment,并且返回新 extent 的第一个数据块。
如果 UNDO 表空间不够了,则从 offline 状态的 Undo Segment 中去偷取过期(expired)的 extent,分配给 Undo segment,并且返回该 extent 的第一个数据块。
如果 offline 状态的 Undo Segment 中没有过期(expired)的 extent,则从 Online 状态的 Undo Segment 中偷取过期(expired)的 extent,分配给 Undo segment,并且返回该 extent 的第一个数据块。
如果 Undo 表空间的数据文件是可扩展的,则扩展 Undo 表空间的数据文件,并且从中分配新的 extent 给 Undo segment,以及返回该 extent 的第一个数据块。
降低 Undo 保存期限参数(undo_retention)10%,并从释放的空间中偷取 extent。
从 offline 状态的 Undo Segment 中偷取非过期(unexpired)的 extent。
重复使用现有 Undo Segment 中非过期(unexpired)的 extent。如果所有 extent 都处于忙碌状态,即都包含了未提交的信息,则跳到第 10 步。否则,跳到 (wrap) 下一个 extent。
从 online 状态的 Undo Segment 中偷取非过期(unexpired)的 extent。
如果上述所有尝试都失败了,则 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′;
确定 UNDO 表空间的数据文件是否为可扩展的:
select autoextensible from dba_data_files where tablespace_name=’UNDOTBS1′;
按状态统计 Undo Extents:
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 表空间扩容了。
关于 Bug 5442919
如果有过期(expired)的 Undo Extent,意味着这些 extent 是可以被重用的。但系统却报出 ORA-30036,则很有可能是撞上 Oracle Bug 5442919 了。以下就是满足该 Bug 的所有条件:
undo_management=auto。
Undo 表空间包含的数据文件均不能自动扩展。
DML 操作失败并报 ORA-30036 错误,同时被写入 log 日志文件。而且 alert.log 中重复显示”Failure to extend rollback segment us#”,其中 us# 为相同值。
实例运行时间达到 1 小时以上。
系统存在大量 offline 的 Undo Segment,例如 1000 个以上。
select count(*) from dba_rollback_segs where status=’OFFLINE’;
Undo 表空间满了。
存在大量过期(expired)或者非过期(unexpired)的 Undo Extent。
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 服务部门支持了。
感谢各位的阅读!关于“Oracle 中如何解决 ORA-01555 错误”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!