首先了解Oracle在什么情况下会产生ORA-01555错误:
假设有张table1的表,里面有6000万行数据,假设预计全表扫描1次需要2个小时,从过程来看:
1、在1点钟,用户A发出了select * from table1;此时不管将来table1怎么变化,正确的结果应该是用户A会看到在1点钟这个时刻的内容。
2、在1点30分,用户B执行了update命令,更新了table1表中的第4000万行的这条记录,这时,用户A的全表扫描还没有到达第4000万条。毫无疑问,这个时候,第4000万行的这条记录是被写入了回滚段,假设是回滚段UNDOTS1,如果用户A的全表扫描到达了第4000万行,是应该会正确的从回滚段UNDOTS1中读取出1点钟时刻的内容的。
3、这时,用户B将他刚才做的操作提交了,但是这时,系统仍然可以给用户A提供正确的数据,因为那第4000万行记录的内容仍然还在回滚段UNDOTS1里,系统可以根据SCN到回滚段里找到正确的数据,但要注意到,这时记录在UNDOTS1里的第4000万行记录已经发生了重大的改变:就是第4000万行在回滚段UNDOTS1里的数据有可能随时被覆盖掉,因为这条记录已经被提交了!
4、由于用户A的查询时间漫长,而业务在一直不断的进行,UNDOTS1回滚段在被多个不同的transaction使用着,这个回滚段里的extent循环到了第4000万行数据所在的extent,由于这条记录已经被标记提交了,所以这个extent是可以被其他transaction覆盖掉的!
5、到了1点45分,用户A的查询终于到了第4000万行,而这时已经出现了第4条说的
情况,需要到回滚段UNDOTS1去找数据,但是已经被覆盖掉了,于是就出现了ORA-01555错误。
解决办法:
1. 扩大回滚段,因为回滚段是循环使用的,如果回滚段足够大,那么那些被提交的数据就能保存足够长的时间,使那些大事务完成一致性读取。UNDO表空间设的足够大
2. 增加undo_retention时间,因为UNDO回滚段是循环使用,里面的数据可能随时被循环覆盖掉,如果设置undo_retention时间更长,那么在retention规定的时间内,任何其他事务都不能覆盖这些数据。
3. 最重要的一点就是优化程序相关查询语句,减少查询语句的一致性读,降低读取不到回滚段数据的风险。所有的出错信息都会纪录到数据库日志alert_PROD.log文件中,检查log文件找到相应的SQL词句,把这条语句提供给开发人员来分析和优化程序代码。比如把一个大的查询分解成几个小的查询等
查看本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/database/Oracle/