Email: service@parnassusdata.com 7 x 24 online support!
ORA-01555: 快照过旧: 回退段号 (名称为 "") 过小的主要发生原因以及应对方法 2014/03/16 BY MACLEAN LIU 暂无评论
本文地址: http://www.askmac.cn/archives/ora-01555.html
如果自己搞不定可以找诗檀软件专业ORACLE数据库修复团队成员帮您恢复!
诗檀软件专业数据库修复团队
服务热线 : 13764045638 QQ号:47079569 邮箱:service@parnassusdata.com
说明ORA-1555的主要发生原因以及应对方法。
[错误信息]
ORA‐01555 snapshot太旧了:回滚段编号string、名字 “string”太小
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
原因:一致读入中所需要的回滚记录被其他用户覆盖了
。
对应方法:使用自动UNDO管理模式时,请增加UNDO_RETENTION的设定值。不使用时,请使用更大的回滚段。
[技术说明]
‐ 错误内容的解读以及发生错误时的对应方法
错误内存因为oracle读取一致性所需要的Before-image被覆盖了等等理由没有获得成功,就会作为错误输出。回滚段(后文中是RBS)是由很多的UNDO块变成的,Before-image被储存在UNDO块上。
一般而言,错误原因是以下两点。
- RBS的数量因为尺寸不够,需要读取一致性的Before-image就被覆盖了
- 发生ORA‐1555 的SQL执行了较长时间(cursor的话,从启动后经过了较长时间)
ORA‐1555发生时,首先想到的对应方法是重新执行ORA-1555所发生的处理。大部分情况,通过重新执行,可以回避ORA-1555的错误。
但是,如果是使用只读事务,发生块故障,media故障等即使重新执行也会发生ORA-1555所以需要终止那个事务,修复故障等。
重新执行也会反复发生ORA-1555的案例中,请以这次的文章中所展示的基本的对策、详细的原因以及解决方法为参考,去除引发ORA-1555的原因。
- 抑制ORA‐1555发生的对应方法,如下所示。
- Oracle8i 以前,UNDO_MANAGEMENT=MANUAL 的情况
- 增加RBS的数量、尺寸
Oracle9i 以后, UNDO_MANAGEMENT=AUTO的情况
- 增加undo表区域的尺寸
-
增加初始化参数UNDO_RETENTION 的值。UNDO_RETENTION参数在commit之后,保存UNDO信息的期间(单位:秒)。但是,无法充分确保UNDO区域时,因为需要保持的UNDO会被覆盖,所以需要配合UNDO表区域的尺寸来增加。
- 基本而言,ORA-1555在搜索语句中发生时,将那个搜索语句的执行所耗费的时间UNDO_RETENTION设定为更大的值。用UNDO_RETENTION指定的期间的UNDO为了课可以保存,几乎在很多的案例中都可以通过增加undo表区域尺寸来抑制该问题的发生。
- 重新审视应用以及条约
- 减少长时间启动的SQL语句以及cursor
- 发生ORA‐1555的SQL语句的执行中,抑制其他事务的更新处理,就会变得很难覆盖其他必要的UNDO块。
- 错误内容的详细说明
Oracle中最低也会在各个SQL语句中保证读取一致性。换言之,用户会返回保证了发行SQL语句时的一致性的数据。因此,执行搜索的用户不会发现在搜索中被其他用户变更的数据。
Oracle根据系统变更编号System Change Numbers (SCN),可以识别数据库的状态。因为SCN发生了commit,随着时间肯定会增大。使用这个SCN可以实现读取一致性。
读取一致性是通过RBS来实现的。
事务多次变更时,Before-image会储存在RBS上的UNDO块中。和名字一样,使用Before-image会执行回滚。在数据库的一部分头中,会记录哪里的RBS的UNDO块被使用了。同样地,数据库会保存最后被commit的SCN的值。
由此,搜索中,其他用户改写了数据,使用UNDO块,通过回滚被改写的数据,其用户可以读取更新前的before image。
这些before image在保存时,对执行更新的事务进行commit。在commit事务时,虽然并不是删除UNDO块的内容,使用过的UNDO块,通过新发行的事务等使用,就会被覆盖删除。
ORA-1555的内容就是因为读取一致性,试着读入使用UNDO块的其他事务的变更前的数据,但已经无法获得储存了必需的数据的UNDO块了。
因此读取一致性,为了减少查看旧UNDO块信息,可以减少事务的执行时间。或者,为了防止必要的UNDO块被覆盖,一般的对应方法就是扩大RBS。
[原因的指定方法]
发生这个错误时,请考虑以下原因。
详细内容请查看后述记载,为了推测到底是什么原因引发了错误,需要收集以下信息。
- 在那个SQL语句中发生了ORA-1555
这是应用的日志中,发生了ORA-1555时,指定执行过的SQL语句。
Oracle9i Database Release2 以后的版本中,发生ORA-1555时以下的信息就会被警报日志记录,这时发生了ORA-1555时,我们就可以知道执行过的SQL。(除去后述(原因4)的LOB的案例以及不是执行中的SQL语句的案例(比如:直接路径输出))
Wed Jul 30 15:04:53 2003
ORA‐01555 caused by SQL statement below (Query Duration=1 sec, SCN: 0x0000.000253f2): Wed Jul 30 15:04:53 2003
select c1 from t1 where c2=’1′
在这里的例子中,会表示出 Query Duration 。UNDO_MANAGEMENT=AUTO 的情况时,比记录于此的数值在UNDO_RETENTION中设定得更大。
在以前的发行中,会在初始化参数中会追加以下内容。
event=”1555 trace name errorstack level 1″
重启数据库之后,发生ORA-1555时,就会输出追踪文件。就会在开头中记录以下发生ORA-1555时的SQL语句。(但是排除后述【原因4】的LOB的案例以及不是执行中的SQL语句的案例(比如:直接路径输出))。
- SESSION ID:(8.24) 2003‐07‐31 20:14:24.950
- 2003‐07‐31 20:14:24.950
ksedmp: internal or fatal error
ORA‐01555: snapshot too old: rollback segment number 2 with name “???” too small Current SQL statement for this session:
select c1 from t1 where c2=’1′
- 到底是哪个RBS中发生了ORA-1555 (UNDO_MANAGEMENT=AUTO 的话不需要检查)
一般来说,错误信息中,因为记录了RBS的编号以及名称,请利用这个。
ERROR at line 1:
ORA‐01555: snapshot too old: rollback segment number 2 with name “RBS2” too small ORA‐06512: at line 2
仅仅记录了编号时,RBS的名称通过以下SQL语句来指定
SQL> select segment_name from dba_rollback_segs where segment_id=<rbs number>;
SEGMENT_NAME
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
RBS2
[发生原因以及对应方法]
ORA‐1555 发生的原因如下所示。在此,我将叙述发生原因以及对应方法。
以下的例子中,请读出接下来两个开头。到底是哪个cursor、SELECT语句接受了ORA-1555。
・RBS中没有发现的是哪个处理哪个信息。
(原因1)
最典型的案例
耗费时间的搜索在执行搜索时,其他事务就会更新,执行commit的情况。
SCN | TransactionA(TRAN:A) | TransactionB(TRAN:B) Other Transactions |
10 | select … from TabA | |
20 | : | update TabA |
30 | : | commit |
40 | : select执行中 | 多数的更新、commit |
: | ||
50 | ORA‐1555 |
这个案例中,TRAN:A是 SCN:10 开始搜索。根据读取一致性的规则, TRAN:A必须读入SCN:10 的时点中的TabA的数据。但是,由于TRAN:B, SCN:20中,TabA会被更新,之后就会进行commit。TRAN:A是由于TRAN:B在读入变更前的数据,需要TRAN:B所使用额RBS的内容,但是因为TRAN:B已经在commit了,因此就会发生了ORA-01555。
另外,在上述例中,变成了select执行中。Oracle在搜索中,需要不少时间的案例,但SCN:10启动cursor,之后,与经过SCN:50执行fetch的案例相同。
(对应方法1)
这个案例中,原因有以下三点。
- TRAN:A长时间执行SQL,或者长时间启动cursor
- 将TRAN:A所执行搜索的表在TRAN:B中执行更新
- TRAN:B所使用的UNDO块会被覆盖或者被开放
因此,对策如下
- 为了减少ORA‐1555发生的搜索处理会重新审视搜索语句的调优以及应用。
- ORA‐1555发生的搜索的执行中,对于搜索对象表不执行更新处理
- UNDO块的覆盖或者抑制开放
Oracle9i 以后, UNDO_MANAGEMENT=AUTO的情况:
- 增加初始化参数 UNDO_RETENTION的值
- 增加undo表区域的尺寸
Oracle8i 以前,UNDO_MANAGEMENT=MANUAL的情况:
- 增加RBS的数量、尺寸
- 重新准备较大的RBS, TRAN:B中明确分割那个较大的RBS。 (使用SET TRANSACTION ROLLBACK SEGMENT …)
- 设定OPTIMAL时,扩大那个设定
(原因2)
通过插入commit使用cursor的案例
Oracle的方法中,启动cursor后,即使是执行commit时,然后利用那个cursor,可以继续执行fetch可以推测以下案例。
SCN | SessionA(SESS:A) |
10 | open cursor (select … from TabA) |
20 | fetch row |
30 | update TabA, commit |
40 | fetch row |
50 | update TabA, commit |
60 | fetch row |
: | |
70 | fetch row ‐‐> ORA‐1555 |
这时,cursor中取出的记录是SCN:10的时点的TabA的数据,不会反映SCN:30以及SCN:50的内容。因此,从cursor取出记录时,需要读入SCN:30以及SCN:50变更前的数据。这时,SESS:A自身就是原因1中的完成SESS:A以及SESS:B二者的功效。SCN:30以及SCN:50更新是所使用的RBS丧失时,就会发生ORA-1555。
(对应方法2)
这个案例中,主要原因是以下两个要素。
- 对成为cursor搜索对象的表进行更新
- 更新之后,因为执行了commit,undo块会被覆盖或者被重新开放。
因此,对应方法如下所示。
- 为了不要重新执行搜索与更新,请重新审视应用
- 不进行commit,或者减少commit的次数,可以降低UNDO块被覆盖的可能性
- 防止UNDO块被覆盖
Oracle9i 以后 UNDO_MANAGEMENT=AUTO时
- 增加初始化参数 UNDO_RETENTION 的值
- 增加UNDO表区域的尺寸
Oracle8i 以前,UNDO_MANAGEMENT=MANUAL 时
‐ 增加RBS的数量与尺寸
- 重新准备较大的RBS,对TRAN:B分配较大的RBS
(使用SET TRANSACTION ROLLBACK SEGMENT …)
(原因3)
与block client相关的案例
上述的两个案例中,都在发生发生oracle-1555搜索的执行中,对成为搜索对象的表进行更新。但是,如果与block clean out相关的话,并不一定需要对搜索执行中的相同的表进行更新。
事务的commit信息保存在数据块以及事务表两个地方。这个信息中包含是否被commit以及commit时的SCN等信息。更新数据之后,进行commit时,RBS中一定会记录commit信息。但数据块中并不一定会记录commit的信息。这是为了让commit能够高效完成。在其他的事务中,对应的数据库搜索时,对应的数据块被搜索到时,就会发生“block clean up”。这时,数据块的事务信息就会被更新,在数据库中也会表示已经被commit了。执行了commit的SCN,或者至少在这个SCN中记录为commit完成的信息。
由此,我想到了以下案例。
SCN | TransactionA(TRAN:A) | TransactionB(TRAN:B) Other Transactions |
10 | update TabA | |
20 | commit; | |
: | ||
110 | select … from TabA | |
120 | : | |
130 | : | |
140 | : select执行中 | 大部分的更新、commit |
: |
150 ORA‐1555
TRAN:A在执行搜索之前,TRAN:B对成为搜索对象的表进行更新。这时TRAN:A只要读取TRAN:B执行的变更就行了,但在以下的脚本中会发生ORA-1555
- TRAN:B执行了commit,但对于更新对象的TabA上的块(BL:1)不会记录commit信息。BL:1上中是还没确定(commit)TRAN:B的更新的状态。
2. 之后,SCN:110中,TRAN:A开始了对TabA的搜索。但是,这时对于BL:1没有执行block clean up.。(换言之,在BL:1上,TRAN:B的更新还是没有被确定(commit)的状态)
- TRAN:A开始搜索TabA之后,直到对BL:1执行block clean up之间,除TRAN:A、B以外,大部分事务都会被执行。这些事务中,使用与TRAN:B相同的RBS,TRAN:B为了更新TabA所使用的信息就会被覆盖。
- TRAN:A读入BL:1。BL:1中,TRAN:B执行的更新没有被commit的状态中残留着。 TRAN:A为了读取一致性,需要确定TRAN:B的状态。如果TRAN:B因为比SCN:110更早commit的话就会读入TRAN:B的内容,SCN:110以后commit的话,就不得不读入TRAN:B变更前的before image。
- TRAN:A为了确认TRAN:B的状态而残留在BL:1中的。TRAN:B将使用过的RBS的信息为基础参考RBS。但是,像3一样,TRAN:B的信息因为其他的大部分事务都已经被执行了,所以就会被覆盖。
- TRAN:B使用过的RBS信息,被其他事务覆盖了就是TRAN:B自身完结了。但是因为关于TRAN:B所有信息都已经被覆盖了,就无法获得对TRAN:B执行commit的正确的SCN。
- TRAN:AはTRAN:Bがコミットを行った正確なSCNを確認するために、TRAN:Bが使用していたRBSのトランザクション・テーブル自体に加えられた変更をロールバックしていき、TRAN:Bがコミットを行ったSCNがSCN:110より前か後かを確認しようとします。これはトランザクション・テーブルに加えられた変更も、UNDOブロックに記録されているからです。
- 对TRAN:B所使用的RBS的事务表自身的变更,最终事务表的回滚中所需要的UNDO块会被覆盖,TRAN:B commit过的SCN以及SCN:110的大小关系无法确定时,就会发生ORA-1555。
- 如果,回滚事务表时,TRAN:B中存在使用过的线程以及使用同样线程的事务的话,直到那个事务在SCN:110中被commit的为止,为了使得SCN:110>事务>TRAN:B这样的关系式成立,需要确定TRAN:B直到SCN:110为止被确定。
这时,因为无法发现必需的UNDO块时,就会发生ORA-1555。
另外,必要的UNDO块就是指检查开始后制成的项目。换言之,直到SCN:110之前,事务都无法回滚,所以也就无法决定TRAN:B以及SCN:110之间的大小关系,就会发生ORA-1555。
另外,这些案例中,更新BL:1后,首先读入的是TRAN:A,除TRAN:A以外的事务,在读入BL:1时也会发生同样的现象。读入完成的事务字执行block clean out时,前述的步骤5、6中,不知道正确的commit SCN的话,之后TRAN:A读入BL:1时,沿着前述的步骤进行,commit了 TRAN:B的SCN以及自身所搜索中所使用的与SCN:110之间的大小关系就无法判断,请考虑是否发生了ORA-1555。
(对应方法3)
这个案例中,以下三个要素就是问题的原因。
- TRAN:A的搜索之前,不执行block clean out。
- TRAN:A的搜索执行中,为了执行多数事务,TRAN:B使用过的事务表就会被覆盖。
- 在覆盖TRAN:B的事务表时,就会失去UNDO块信息的覆盖或者开放。
因此,对应方法如下所示。
- Tab:A被再次更新前,执行搜索处理。
- 发生了ORA‐1555的搜索处理在执行前,通常会执行block clean out。对表只要执行block clean out就够了,但对于索引块,也需要执行block clean out。
表的block clean out:
SQL> SELECT /*+ FULL(表名) */ COUNT(*) FROM 表名;
索引的block clean out:
- 制成B‐Tree索引时
SQL> SELECT /*+ INDEX(表名索引名) */ COUNT(*) FROM 表名
2 > WHERE 索引列 IS NOT NULL;
- 符合索引时,作为搜索对象列,指定所有的索引列。WHERE语句的条件是符合索引的头列IS NOT NULL 。
- 制成bit map时
SQL> SELECT /*+ INDEX(表名 索引名) */ count(*) FROM 表名
- 为了缩短发生ORA‐1555的搜索处理,就会重新审视搜索语句的调优以及应用。
- 抑制事务表被覆盖的可能性
- 不执行commit或者减少commit的次数
- Oracle8i 以前,UNDO_MANAGEMENT=MANUAL 的情况
- 增加RBS的数量
- 指定了TranB相应的处理时,另外准备为了执行TranB的回滚段,终止后使其offline。
具体来说
- TranB开始前,将回滚段(以后是R1)进行offline
- 用SET TRANSACTION USE ROLLBACK SEGMENT 语句进行明确地指定,或者将其他的回滚段进行offline,使得TranB使用回滚段R1
- TranB处理完成后,必要的话,在进行shrink之后,将回滚段R1进行offline。
- 中offline过的回滚段再进行offline
- 防止UNDO块被覆盖,
Oracle9i 之后 UNDO_MANAGEMENT=AUTO时
- 增加初始化参数 UNDO_RETENTION 的值
- 增加undo表区域的尺寸
Oracle8i 以前、UNDO_MANAGEMENT=MANUAL 时
- 增加RBS的数量、尺寸
- 重新准备较大的RBS,在TRAN:B中明确地分割较大的RBS
(使用SET TRANSACTION ROLLBACK SEGMENT …)
- 设定了OPTIMAL时,扩大其设定
- 0.1以后,直接加载或者直接插入中的变更,上述方法中,就不会被clean。这是为了提高搜索性能的变更。
因此,TranB在直接加载中,用相应的案例,作为对应方法,不会采用2.以外的方法。
(原因4) LOB段中发生了ORA-1555的案例
LOB列被储存在LOB段中时,对于LOB列追加的变更的UNDO信息不会写入到RBS中,会在LOB段中执行处理。
具体而言,执行更新时,获得新的块,在此写入变更后的的LOB数据。变更前的LOB数据就此保留,执行回滚时会被再次使用。Commit之后,变更前的LOB数据就此留存。读取一致性就会被使用。变更前的LOB数据会以可以被覆盖的状态留存,需要新建块时,就会使用旧的项目。为了读取一致性,需要的数据被覆盖了消失时,就会发生ORA-1555。
- 内嵌LOB,换言之,LOB列与原来的表储存在同一段中时
- UNDO信息与一般的案例同样地被写入到RBS中,所以原因和1-3一样。
- 案例中发生了ORA-1555 。
这时典型的案例如下所示。
# TabA的列c1作为LOB列。 | ||
SCN | TransactionA(TRAN:A) | TransactionB(TRAN:B) Other Transactions |
10 | select c1 from TabA | |
20 | : | update TabA.c1 |
30 | : | commit |
40 | : select执行中 | 更新大部分TabA.c1 |
: |
- ORA‐1555
- TRAN:A开始了需要SCN:10的时点的c1的数据的搜索
- TRAN:B变更需要TRAN:A的行的c1列的值,进行commit。这时,更新前的列值还残留在LOB段上。
- 更新其他的c1列的事务,更新前的数据就会被覆盖。
- TRAN:A不会读取更新前的数据,就会发生ORA-1555.
这个案例中,伴随着以下的错误信息,ORA-1555中不会记录RBS的编号以及名称。请注意ORA-22924是否有同时发生。
SQL> select c2 from t1;
ERROR:
ORA‐01555: snapshot too old: rollback segment number with name “” too small ORA‐22924: snapshot too old
(对应方法4)
这个案例中,原因如下所示。
- TRAN:A的搜索在执行中,会对LOB列执行大部分更新处理
- TRAN:B更新前的数据就会被覆盖
因此,对应方法如下所示
- 为了不同时进行搜索与更新,需要重新审视应用
- 为了防止更新前的数据所残留的LOB段被覆盖,需要扩大LOB段PCTVERSION值
LOB列PCTVERSION值可以通过以下SQL来确认
SQL> select pctversion from user_lobs
- where table_name='<表名>’ and column_name='<列名>’;
PCTVERSION
‐‐‐‐‐‐‐‐‐‐
10
PCTVERSION的值可以通过以下SQL来变更
SQL> alter table <表名> modify lob ( <列名> ) (pctversion <新建PCTVERSION值>);
(原因5)
使用READ ONLY事务的案例
Oracle的READ ONLY事务,读入在事务开始后的数据。执行这样水平的读取一致性。一般的READ WRITE事务中,因为是SQL语句单位的读取一致性,需要读入比那更旧时点的数据。因此,比起一般的READ WRITE事务就更容易发生ORA‐1555。如果获得(原因1)的案例的话
SCN | TransactionA(TRAN:A) | TransactionB(TRAN:B) Other |
10 | set transasction read only; | |
20 | update TabA | |
30 | commit | |
40 | 大部分更新、commit |
- select from TabA
- SCN:10中TRAN:A开始了READ ONLY事务
- 根据TRAN:B对TabA进行更新、commit变更。
- 由于大部分的事务,TRAN:B使用过的UNDO块就会被覆盖
- TRAN:A对TabA执行搜索。TRAN:A在SCN:10时需要TabA的数据。
- TabA由于TRAN:B来执行更新,所以TRAN:A利用TRAN:B所使用的UNDO块来制成before image,因为UNDO块已经被覆盖了,所以就会发生ORA-1555。
READ ONLY事务的案例中,执行与至此不同的搜索语句的更新时,不需要commit。所以就容易发生ORA-1555。
(对应方法5)
这个案例的情况的原因如下所示。
- TRAN:A使用READ ONLY事务
- 在READ ONLY事务执行中, READ ONLY事务会执行成为搜索对象的表的更新
因此,对应方法如下所示
- 不使用READ ONLY事务
- 在READ ONLY事务执行中,不执行READ ONLY事务的更新
(原因6) RBS被删除或者被破坏
至此介绍过的例子中,执行RBS的参考时,请考虑RBS被drop rollback segment删除的情况。这时,因为无法参考RBS的内容,就会发生ORA-1555。但是,为了知道事务的正确commit时刻,参考RBS时,因为删除了RBS时的SCN会残留在数据库上,至少在那个事务中事务执行了commit。
另外,RBS发生了块故障的情况中,因为无法参考RBS的内容,所以可能发生ORA-155(展示块故障的错误)。
(对应方法6)
被块故障、media故障破坏的案例中,因为重新执行还是会发生ORA-1555,首先需要执行故障恢复。因为RBS被删除了,所以在发生ORA-1555的案例中,请尽可能减少删除RBS。
(原因7)
使用数据库链接的案例
在使用数据库链接的分散事务中,可能会发生比访问单个数据库时更复杂的问题。着是因为通过数据库链接来连接的数据库中各自由不同的SCN来管理的。
详细内容请参考Document 1744230.1
比如,Materialized views刷新时,可能发生预料之外的ORA-1555。详细内容请参考
Document 1731156.1(KROWN:99762) をご参照下さい
[获得信息]
作出上述调查以及对策之后还是无法抑制发生ORA-1555的话,请将至此的调查结果。发生错误的应用处理内容、发生错误时所执行的其他的事务信息、以及发生ORA-1555时的错误信息,上传到新建的TAR中。