ORA-01555错误

 

Tue Nov 17 09:49:02 2009
ORA-01555 caused by SQL statement below (SQL ID: 98s35x4tpqm5d, Query Duration=0 sec, SCN: 0x0000.02258a47):
Tue Nov 17 09:49:02 2009
INSERT into SYS_TEMP_FBT SELECT :1, :2, :3, rowid, SYS_FBT_INSDEL FROM DUREX.T_1116 as of SCN :4 S

 

假设有张表,叫table1,里面有5000万行数据,假设预计全表扫描1次需要1个小时,我们从过程来看:

1、在1点钟,有个用户A发出了select * from table1;此时不管将来table1怎么变化,正确的结果应该是用户A会看到在1点钟这个时刻table1的内容。这个是没有疑问的。
2、在1点30分,有个用户B执行了update命令,更新了table1表中的第4000万行的这条记录,这时,用户A的全表扫描还没有到达第4000万条。毫无疑问,这个时候,第4000万行的这条记录是被写到了回滚段里去了的,我假设是回滚段RBS1,如果用户A的全表扫描到达了第4000万行,是应该会正确的从回滚段RBS1中读取出1点钟时刻的内容的。(未更新前的数据)
3、这时,用户B将他刚才做的操作commit了,但是这时,系统仍然可以给用户A提供正确的数据,因为那第4000万行记录的内容仍然还在回滚段RBS1里,系统可以根据SCN来到回滚段里找到正确的数据,但是大家注意到,这时记录在RBS1里的第4000万行记录已经发生了一点重大的改变:就是这个第4000万行的在回滚段RBS1里的数据有可能随时被覆盖掉,因为这条记录已经被提交了!
4、由于用户A的查询时间漫长,而业务在一直不断的进行,RBS1回滚段在被多个不同的tracnsaction使用着,这个回滚段里的extent循环到了第4000万行数据所在的extent,由于这条记录已经被标记提交了,所以这个extent是可以被其他transaction覆盖掉的!
5、到了1点40分,用户A的查询终于到了第4000万行,而这时已经出现了第4条说的情况,需要到回滚段RBS1去找数据,但是已经被覆盖掉了,于是01555就出现了。

前面提到了ORA-01555错误,那么现在来看一下ORA-01555错误是怎样产生的。由于回滚段是循环使用的,当事务提交以后,该事务占用的回滚段事务会被标记为非活动,回滚段空间可以被覆盖重用。那么一个问题就出现了,如果一个查询需要使用被覆盖的回滚段构造前镜像实现一致性读,那么此时就会出现Oracle著名的ORA-01555错误。

ORA-01555错误的另外一个原因是因为延迟块清除(Delayed Block Cleanout)。当一个查询触发延迟块清除时,Oracle需要去查询回滚段获得该事务的提交SCN,如果事务的前镜像信息已经被覆盖,并且查询SCN也小于回滚段中记录的最小提交SCN,那么Oracle将无从判断查询SCN和事务提交SCN的大小,此时出现延迟块清除导致的ORA-01555错误。

另外一种导致ORA-01555错误的情况出现在使用sqlldr直接方式加载(direct=true)数据时。当通过sqlldr direct=true 方式加载数据时,由于不产生重做和回滚信息,Oracle直接指定Cached Commit SCN 给加载数据,在访问这些数据时,有时会产生ORA-01555错误。

下面我来谈谈自己平时解决ORA-01555错误的基本步骤,希望对大家有所帮助

0. 开始先看看rollback segment是否有分配不当的问题,例如莫一个rollback segment(报错的那个)太小。

如果有,先recreate rollback segment以保持所有的回滚段大小一致,并且size不要太小。

1. 看查询的执行计划是否正确。ORA-01555错误发生的概率和查询所需的时间成正比,查询时间越长,发生ORA-01555的概率越大。

如果执行计划不正确,首先进行sql tuning,如果执行计划正确,但进行fts,考虑是否可以并行来跑(server load不是很高的情况下)

总之一句话就是尽量缩短query的时间

2. 如果执行计划正确,估算一下运行时间,如果运行时间不是很长,这时候我喜欢登陆到server本地上执行一下SQL看看需要多少时间

如果本地很快就执行完了,说明问题出在application媏,转入下面第三点。如果确实很慢,转入第四点。

3. Application媏的问题可能类型很多,我所遇到的大致有一下几种

3.1 网络速度太慢,application server和database server的网络出现问题。这时候dba可以从application server断来做一些ping包的测试。

如果确实是网络的问题,可以找网络工程师协助察看是否有网络故障。如果异地之间确实速度很慢,可以考虑是否从一台速度比较

快的application server上发出查询请求。

3.2 Cursor open时间太长。有时候application媏是使用open cursor的方式来fetch data。这时候有可能open cursor后长时间不做操作,导致fetch data时

出现ORA-01555。更常见的一种情况是,有些应用是将一些处理程序放置在fetch loop中,例如

declare

cursor cur_query is select object_id from dba_objects;

…..

begin

for i in cur_query loop

….

&do some things here

end loop;

end;

/

这时候可能整个查询的速度被”&do some things here“这段处理程序的速度所影响,导致整个查询速度变慢。

可以建议application修改code,将数据先fetch出来存在一个structure中,然后再来处理。

3.3 commiting in a loop,这一点在Tom kyte的Expert Oracle Database Architecture中有详细的例子(P268),在itpub上有一篇帖子遇到的就是这个问题。

4. 这时候我们要考虑一下数据库本身了。首先看看产生这么多undo 信息是否正常,如果正常的话,考虑是否可以挑选一个系统比较空闲的时段跑查询。

如果本身查询运行的时间就是系统比较空闲的时段或者系统从来就没闲过:), 那就加大回滚段吧。

这里有两种方法,

第一种是重建回滚段,修改minextents为一个较大的值,一个一个的offline,drop,create。初始化的大小为minextents*extent size

第二种是增加回滚段的个数

8i在有些情况下oracle会很喜欢用第一个回滚段,不知道为何,可以考虑将第一个回滚段扩大一点(如果错误信息里面是第一个回滚段的话)

在8i中删除回滚 tablespace 重建回滚 tablespace (name是回滚 tablespace 名称)。
drop tablespace name including contents

再增加回滚段 (一般是RB1-RB15)
CREATE PUBLIC ROLLBACK SEGMENT RB1
TABLESPACE RBS
STORAGE(INITIAL 10M NEXT 10M MINEXTENTS 2 MAXEXTENTS 1024 OPTIMAL 20M)
/
ALTER ROLLBACK SEGMENT RB1 ONLINE
/

我比较喜欢使用的是第一种方法

5. 如果第四步仍然没有效果(我们不可能无限制的加大回滚段),那么可以考虑其他的方法

如果有standby database的话,可以考虑将其open read only来给大的查询使用,或者为其建立一个报表系统

对于ORA-01555比较频繁的系统,可以考虑转为auto management undo tablespace,这样管理起来简单一点。

auto管理下处理的基本思想是,获得最长查询的时间,预估keep这段时间undo所需的回滚段大小,扩大undo tablespace,修改undo_retention

这里推荐一篇文章讲解auto undo management的文章,讲解还是比较详细的 auto undo management.pdf (右键点击下载)

另外关于LOB存在的情况,是完全不同的一种情况,我以前有文章写过 ,请参考 当ORA-01555遇到了LOB

当然这里短短的描述还是不能涵盖ORA-01555 。实际处理问题的时候也不必拘泥于具体的步骤。

理解了基本原理,再辅以实际案例的解决,这样才会有一个真正意义上的理解。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值