深度解析ORA-01555 原因及解决方法

it2026-04-06  3

两种原因:

一致读 ,CR (consistency Read) 查询修改数据的前镜像时,前景镜像被覆盖。块延迟清理 事务工作步骤 Transaction 开始前 回滚段获取一个ITL(事务槽),分配空间, 记录事务信息 Transaction 提交后,redo完成记录,同时还清除回滚段的事务信息 包括行级锁,ITL信息(commit 标志,SCN等) 清除这些事务段的信息的过程就叫做 块清除, 在完成块清除时, 我们本事务修改的数据块就会存在两种可能 (1) 所有的数据块还保存在 buffer cache 中, (2)部分数据块或者是全部数据块由于LRU管理已经被刷出了buffer cache。oracle为了考虑到块清除的成本,以及性能,会作以下两种方式的块清除处理: 快速块清除(fast block cleanout), 当事务修改的数据库全部保存在buffer cache 并且修改数据块的数据量没有超过 cache buffer 的 10%,快速清除事务信息。 延迟块清除(delayed block cleanout) 当修改的数据块的阀值超过10% 或者本次事务相关的数据块已经被刷出了 buffer cache, oracle 会下次访问此block 时再清除事务信息。

接下来,下一个select(读者)去读延迟块。

如果select 可以找到回滚段中记录的commit 时的SCN,那么延迟块正常清除,出现select产生redo的情况。如果select 找不到commit时的SCN,证明需要清理commit的已经被回收。顺序为: 需要清理的scn(已被回收) < 能找到的最小事务的scn 这时候就需要分析现在select的SCN 在哪个位置: 2.1: select的SCN > 回滚段中最小的scn,及在最小scn之后, 那么完成块清理。 2.2 :select的SCN < 回滚段中最小的scn, 就是还是小于最小的scn 即还是找不到。就发生ORA-01555. oracle 会做设置需要清理的scn(已被回收) = 能找到的最小事务的scn。

++++++++++++++++++++++++

下面简单讲下ORA-1555的处理方法:

在磁盘空间不充足,可以调整undo_retention SELECT d.undo_size/(1024*1024) "ACTUAL UNDO SIZE [MByte]", SUBSTR(e.value,1,25) "UNDO RETENTION [Sec]", ROUND((d.undo_size / (to_number(f.value) * g.undo_block_per_sec))) "OPTIMAL UNDO RETENTION [Sec]" FROM ( SELECT SUM(a.bytes) undo_size FROM v$datafile a, v$tablespace b, dba_tablespaces c WHERE c.contents = 'UNDO' AND c.status = 'ONLINE' AND b.name = c.tablespace_name AND a.ts# = b.ts# ) d, v$parameter e, v$parameter f, ( SELECT MAX(undoblks/((end_time-begin_time)*3600*24)) undo_block_per_sec FROM v$undostat ) g WHERE e.name = 'undo_retention' AND f.name = 'db_block_size'; 在磁盘充足,保证undo_retention不变,调整undo_size SELECT d.undo_size/(1024*1024) "ACTUAL UNDO SIZE [MByte]", SUBSTR(e.value,1,25) "UNDO RETENTION [Sec]", (TO_NUMBER(e.value) * TO_NUMBER(f.value) * g.undo_block_per_sec) / (1024*1024) "NEEDED UNDO SIZE [MByte]" FROM ( SELECT SUM(a.bytes) undo_size FROM v$datafile a, v$tablespace b, dba_tablespaces c WHERE c.contents = 'UNDO' AND c.status = 'ONLINE' AND b.name = c.tablespace_name AND a.ts# = b.ts# ) d, v$parameter e, v$parameter f, ( SELECT MAX(undoblks/((end_time-begin_time)*3600*24)) undo_block_per_sec FROM v$undostat ) g WHERE e.name = 'undo_retention' AND f.name = 'db_block_size'
最新回复(0)