DBA经常碰到的问题之一:
ORA-1555: snapshot too old: rollback segment number 9 with name "R07" too small
虽然在使用undo tablespace后,该错误出现的频率减少,但是还是有必要知道为什么会出现????
这个错误代表的含义是在特定数据库块上的一致性读(consistent get:读取被其他会话改变的块)失败。当事务和查询开始时,将记录当前
的SCN。该SCN将作为查询和事物的快照SCN。这个名词的来源是查询和事务必须得到开始那一刻的一致性快照。
查询用到的每个块必须反映快照那一刻的状态,包括被更新和删除的块。临时重构块与快照SCN一致的版本称为一致性读。
一致性读失败的原因主要有两种:回滚失败,清除失败。
回滚失败
如果自从快照scn以来以任何形式被其他事务更改过,那么为了一致性读这些改变必须被回滚。因此,必须读取那些改变已经写了的回滚段
数据库块。
如果改变由很小的离散事务产生,那么将没有回滚信息。如果这样将会发生ORA-1555。类似的,如果由于包含那些块的回滚段分区在收缩
操作中被释放或者被随后的事务重用,也将发生ORA-1555。
而且需要注意,那么回滚段中不可用的分区从快照scn以来至少被重用过一次。
清除失败
DBWn通常在最后一个事务更改那个块提交之前写块到磁盘。如果这样,块头中相关的事务条目将仍然显示事务在块上有相关的打开,并且
受影响的行的行头中的行级锁仍将被强制保留。当块被其他查询/事务读取时,将会执行block cleanout。该调用找出先前的事务是否已经提交
,并且如果这样,行锁将被清除并且相关的事务提交scn将被记录在块头的相关事务列表条目中。
对于一致性读,为了为相关的事务建立提交scn相对序列号和一致性读的快照scn,快清除是必要的。如果相关事务没有被提交,或者在快
照scn后被提交,此时是需要回滚的。但是如果相关的事务提交在快照scn之前被提交,则不需要回滚。
为了确定一个相关事务的提交scn,并且如果其没有记录在相关的事务列表条目中,或者其不再active,那么有必要查询回滚段头块中的事
务表确定那个事务使用的提交scn。相关事务的回滚段好被编码在相关的事务条目中并且作为事务标识符的一部分。但是回滚段的头块可能不再
包含相关事务的纪录,因为那个块可能已经被改变。
不过,一致性读并不需要确定相关事务的精确提交scn--仅仅需要提交事务的相对序列号以及快照scn。如果一致性读成功,并且相关事务
的事务头不在其回滚段头块的一致性版本中,并且事务标识符指示事务早于快照scn,那么可以推断出相关的事务提交的较早,并且无需回滚。
但是回滚段头块中的一致性读可能失败。如果在快照scn以来,到那个回滚段头块的回滚信息被更改过,那个块将不再可用。由于这些改变
是写入回滚段本身,因此不再可用。但是更多的是由于回滚段事务表的改变,因为事务表中的槽是周期性重用的,回滚段分区本身必须被重用n
次。
减少出现的方法:
·在大型查询/事务运行时不要运行离散的小事务,除非能够确保数据集是排斥访问的;
·调用长时间运行的查询和事务,这样一致性读在快照scn以来不需要回滚改变。同时这也减少了系统负载;
·将长时间运行的事务拆分为一串可重启步骤;
·在运行长时间的事务/查询时收工收缩所有回滚段到它们的最优值以减少由于分区释放导致的一致性读回滚失败。通过可通过以下脚本收
缩:
spool shrink_rollback_segs.tmp
select
'alter rollback segment ' || segment_name || ' shrink;'
from
sys.dba_rollback_segs
where
status = 'ONLINE'
/
spool off
@shrink_rollback_segs.tmp
host rm -f shrink_rollback_segs.tmp -- for Unix
host del shrink_rollback_segs.tmp -- for others
·在所有回滚段上使用较大的最优值,以推迟分区重用。可以通过以下脚本得到回滚段重用的平均时间:
column explain format a53
column explain heading "Average time before rollback segment extent reuse ..."
column hours format 9999999 heading "in hours"
column minutes heading "in minutes"
select
null explain,
trunc(24 * (sysdate - i.startup_time) / v.cycles) hours,
trunc(1440 * (sysdate - i.startup_time) / v.cycles) minutes
from
sys.v_$instance i,
( select
max(
(r.writes + 24 * r.gets) / -- bytes used /
nvl(least(r.optsize, r.rssize), r.rssize) * -- segment size
(r.extents - 1) / r.extents -- reduce by 1 extent
) cycles
from
sys.v_$rollstat r
where
r.status = 'ONLINE'
) v
/
·不要交叉提交推进。就是说不要在最后一个提交之前fetch cursor。特别是游标查询的数据正被当前会话改变;
·使用大的数据库块以最大化回滚段事务表中的槽数,从而推迟槽重用;
·在与长时间事务大约同时运行的任务中减少提交频率,特别是PL/SQL中的循环,以减少事务槽的重用;
·如果必要,增加额外的回滚段是更多的事务槽可用;
对于特别大的查询和事务,需要做的只是防止释放/重用任何在快照scn后的事务使用的回滚段分区。一种简单的方法是确保从快照scn开始
只有一个回滚段online,并且显示使用那个回滚段。
另一种相对复杂的方法是将回滚段中所有未提交的事务保持不提交。不过这会发生回滚段溢出情况,但是相对容易控制。
阅读(900) | 评论(0) | 转发(0) |