ORA-1555错误简单的说就是针对一个数据块产生一致读时发生了错误。一致读就是指ORACLE利用回滚段来临时重构一个和事务或查询开始时的块状态相同的快照块的过程。如果一个块改变了多次,可能就会有多个快照块的。
一个事务或查询开始执行时,ORACLE会产生一个SCN来记录这个开始时刻点,这个SCN也就叫做SNAPSHOT SCN。ORACLE仅仅看基于SNAPSHOT SCN的快照记录。如果块中有活动的事务或BLOCK SCN> SNAPSHOT SCN时,就产生了一致读。如果是没有活动的事务但没有产生COMMIT SCN的块 ,先产生DELAY BLOCK CLEANOUT,再比较COMMIT SCN与SNAPSHOT SCN的大小,如果COMMIT SCN小于SNAPSHOT SCN则直接使用该块,否则要产生一致读。
产生ORA-1555的可能情况:
1 一个长时间运行的查询,并同时针对查询需要的块有DML处理(主要是update和delete)
2 当查询和插入并发时
3 延迟块清除
4 交叉fetch和commit
5 回滚段发生错误
情况1 一个长时间运行的查询,并同时针对查询需要的块有DML处理(主要是update和delete)
当一个查询开始之后,正好某一个update更改了其中的一个记录,当查询扫描到该记录时,就需要一致读,回滚空间中去查找原值。如果这个查询的时间非常长,而那条记录修改之后,很快就被提交了,导致回滚空间中的记录可以被清除,并且这个数据库事务本身也比较多,回滚空间的覆盖比较块,在查询结束之前,回滚段中的记录空间就被新的记录覆盖占用了,导致查询找不到原值,从而产生ORA-1555错误。
Solution:
1、业务控制,禁止对同一个表的长时间查询和更新处理同时进行,要分开执��
2、增大回滚段的大小
3、增加回滚段的个数
4、不使用OPTIMAL选项,已经被使用的空间就不会很快收缩回来,可以使commit之后的记录保持尽可能长的时间
5、推迟对DML语句的COMMIT
6、优化查询语句,比如并行查询,目的是减小查询的时间
7、为要查询的表建立只读SNAPSHOT,这样对表记录的修改就不会影响到查询,但该表不能是太大的表
情况2 当查询和插入并发时
一般情况下,当我们查询一个表,同时对这个表作插入,这时是不需要一致读的。当然这种情况下也不可能产生ORA-1555错误。
当作全表扫描的时候,oracle会扫描所有位于HWM之下的空间,而对于HWM之上的空间将忽略。也正因为如此,当我们插入的数据位于HWM之下的时候,如果同时还有例如全表扫描这部分空闲的空间,就会产生一致读,就有可能会导致ORA-1555错误。特别是在VLDB和OPS系统中,因为在这些系统中,很多时候都会对表作pre-allocate,当作了预分配之后,如果作一次大批量的delete,将会有非常多的可用空间位于HWM之下。
Solutions:
1、情况1的所有解决方法这里同样适用
2、不要预分配区(pre-allocate extent)
3、使用tuncate来删除表记录,使HWM收缩。
4、使用直接路径选项导入数据,使插入的数据在HWM之上。
情况3 延迟块清除
关于延迟块清除的概念,可以参考后面的附录。
Solution:
1、使用oracle并行服务器OPS,将DML操作分割到不同的实例上执行
2、在批处理中使用SET TRANSACTION USE ROLLBACK SEGMENT为事务单独指定一个回滚段。
3、可以在DML之后,立即执行一个全表扫描和analyze indexes来强制立即进行块清除。
情况4 交叉fetch和commit
这种比较典型的情况是在一个过程中使用了如下的结构:
cursor c1 is select * from bigemp;
begin
for c1rec in c1 loop
update mydual set a=a;
commit;
end loop;
end ;
Solution:
1、检查过程,避免这种交叉提取和提交的情况出现。
2、延迟commit
3、在查询语句中,增加“ order by 1 ”的语句,这样会在临时段中保留ORDER BY的结果,可以避免一些一致读。
情况5 回滚段发生错误的解决方法:
由这种原因导致的ORA-01555错误是极少数的。一般情况下,也只有在那些不支持大文件的操作系统会发生这种情况。
Solution:
1、检查init.ora中的参数文件,show parameter CORRUPT,可以将结果提交给ORACLE SUPPORT SERVICES。如果这样的参数存在,建议重 建数据库。
2、检查操作系统是否支持ORACLE。检查操作系统的错误日志和ORACLE的错误日志。
3、向Oracle Support Services寻求帮助。
补充情况6:
在oracle 9i之后,使用auto的undo,就很少出现ORA-1555错误了,但是也不能完全排除这个错误,比如以下错误:
ORA-01555 caused by SQL statement below (Query Duration=11952 sec, SCN: 0x0842.1a1d737c)
这种情况下,主要是查询的时间超长,超过了undo_retention设置的时间10800秒,从而产生前面的情况1和情况2的错误。
Solution:
主要的解决方法,还是优化查询,包括语句的优化和索引的优化。