1、导数据遇见 ORA-01555 错误昨天在对 CALLCENTER 系统的主库导入 CUSTOMER 数据的时候,遇到了 ORA-01555错误。软件环境:两台 DB 都是 oracle9.2.0.4导入工具使用:powercenter8.6主库是 redhat linux4.7备库是 windows2003(32 位)环境在导入过程中,报:ORA-01555: 快照过旧: 回退段号 1 在名称为 “_SYSSMU1$“ 过小错误。1555 错误产生的原因,就需要知道 ORACLE 的两个特性:一致性读(Consistent Get)和延迟块清除(Delayed Block Cleanout)
2、。此外,还要知道关于回滚段的一些配置参数:相关参数先看下 Oracle 中关于 UNDO 有哪些配置参数:SQL show parameter undoNAME TYPE VALUE- - -undo_management string MANUALundo_retention integer 900undo_suppress_errors Boolean FALSEundo_tablespace string UNDOTBS1undo_management回滚段的管理方式。值可以为 MANUAL/AUTO。9i 中默认是 MANUAL,10g 中默认是AUTO。从 9i 后,回滚段就以表空间
3、的形式管理,并且支持系统自动管理回滚段。一个回滚表空间上可以创建多个回滚段,一个数据库可以创建多个回滚表空间。但是,一个实例(Instance)只能使用一个回滚表空间。如果 undo_management 设置为 MANUAL,就是手动创建回滚段:SQL create rollback segment undo1 tablespace UNDOTBS1;如果设置为 AUTO, Oracle 就自动管理回滚段的创建,而手工创建就会失败。undo_retention这个参数设置回滚段中的被提交或回滚的数据强制保留时间,单位是秒。请注意,这个参数和1555 错误有非常大的关系。但是,需要提醒的是,并
4、不是回滚段中的数据超过这个时间以后就会被清除掉,而是等到后面事务产生的回滚数据覆盖掉“超期”数据。所以这就是为什么我们往往看到系统的回滚表空间占有率始终是 100%的原因了。undo_suppress_errors是否报与回滚段有关的错误。如果为 FALSE,就不会产生与回滚段有关的错误。但是,请注意,并不是不会发生回滚段错误,而只是屏蔽错误信息,错误发生了就会存在滴。在 10g 中,这个参数是隐含参数。undo_tablespace为每个实例制定的唯一当前使用的回滚段表空间。面我们就模拟一下 1555 错误发生的情况:首先建立测试环境。由于我们只是要模拟 1555 错误的发生,所以需要建立一
5、个小的回滚表空间,并且设置 undo_retention 时间为 1(秒),以便回滚数据尽快被覆盖(呵呵,要防止 1555 错误发生,这就一定要避免的)。CREATE UNDO TABLESPACE rbs_tsDATAFILE rbs_ts2.dbf SIZE10MAUTOEXTEND OFF;altersystem set undo_retention=1 scope=spfile;altersystem set undo_management=auto scope=spfile;altersystem set undo_tablespace=rbs_tsscope=spfile;star
6、tup forcealter tablespace rbs_tsonline;create table demo.t_dualas select * from dual;insert intot_dual values(1);commit;一致性读导致的 1555 错误开始读取表。SQLSQLvar cl refcursorSQL begin2open:clfor select * from demo.t_multiver;3end;4/PL/SQL procedure successfully completed.SQL更新表数据,产生回滚信息。SQL updated mo.t_multiv
7、er set b = 111 where a = 1;1 row updated.SQL commit;Commit complete.运行大批其他事务,充满所有回滚段,以致覆盖上面的回滚信息。回滚段可以通过dba_rollback_segs 查看。SQL begin2for I in 1.20000loop3update demo.t_dualset dummy=1;4commit;5end loop;6end;78/PL/SQL procedure successfully completed.SQL /PL/SQL procedure successfully completed.查询到
8、更新过的数据记录,回滚信息已经被覆盖,所以报 1555 错误。SQLprint :clERROR:ORA-01555: snapshot too old: rollback segment number 18 with name “_SYSSMU18$“toosmallnorows selectedSQL延迟块清除导致的 1555 错误开始读取表。SQLvar cc refcursorSQLSQL begin2open:cc for select * from t_multiver;3end;4/这时一个事务更新了该数据块,但在提交前,我们手工将 buffer cache 中的数据做了flus
9、h,再做提交。这时的数据块上只记录了锁标志,没有事务标志和 Commit SCN。PL/SQL procedure successfully completed.SQLSQL update t_multiver set b=115 where a=1;1 row updated.SQLSQL alter system flushbuffer_cache;System altered.SQLSQL commit;Commit complete.进行非常多的事务,将回滚段中的事务信息表中的数据全部覆盖:SQLSQL begin2-overwriterollback slot3for I in 1.
10、40000loop4 updatet_dualset dummy=1;5commit;6end loop;7end;8/PL/SQL procedure successfully completed.读取数据块前需要到回滚段的事务信息表中读取 Itl 中没有标记完全的事务的状态和Commit SCN,以判断是否需要进行一致性读。但是事务信息表中的数据都已经被覆盖,所以报1555 错误:SQLSQLprint :ccERROR:ORA-01555: snapshot too old: rollback segment number 20 with name “_SYSSMU20$“toosmal
11、lnorows selected以上两个例子看起来是好像很类似,但是,他们的本质区别是:第一个实际上是在进行一致性读得时候发生的 1555 错误,而第二个例子是在判断是否需要进行一致性读得时候发生的 1555 错误。解决 1555 错误的方法现在,我们已经知道了 1555 错误产生的原因。那么,就可以总结出以下方法来解决 1555错误问题:1、扩大回滚段因为回滚段是循环使用的,如果回滚段足够大,那么那些被提交的数据信息就能保存足够长的时间是那些大事务完成一致性读取。2、增加 undo_retention 时间在 undo_retention 规定的时间内,任何其他事务都不能覆盖这些数据。3、优
12、化相关查询语句,减少一致性读。减少查询语句的一致性读,就降低读取不到回滚段数据的风险。这一点非常重要!4、减少不必要的事务提交提交的事务越少,产生的回滚段信息就越少。5、对大事务指定回滚段通过以下语句可以指定事务的回滚段:SET TRANSACTION USE ROLLBACK SEGMENTrollback_segment;给大事务指定回滚段,即降低大事务回滚信息覆盖其他事务的回滚信息的几率,又降低了他自身的回滚信息被覆盖的几率。大事务的存在,往往是 1555 错误产生的诱因。6、使用游标时尽量使用显式游标,并且只在需要的时候打开游标,同时将所有可以在游标外做的操作从游标循环中拿出。当游标打
13、开时,查询就开始了,直到游标关闭。减少游标的打开时间,就减少了 1555 错误发生的几率。在本次操作中,笔者的解决方案是:1.适当增大 undo 表空间的尺寸,防止回滚信息被覆盖。2.增加 undo_retention时间,增加到 10800秒(在导入源和导出源都修改)。3.删除目标表的部分索引,加快导入速度,在倒完数据后,再建立。关于备份数据库报 ora-01555 的解决方法备份 包含大二进制数据提示如下 错误表 ANNEX 将以常规路径导出。. . 正在导出表 ANNEXEXP-00056: 遇到 ORACLE 错误 1555ORA-01555: 快照过旧: 回退段号 在名称为 “ 过小
14、ORA-22924: 快照太旧导出成功终止,但出现警告。问题原因:大二进制的表中 有记录损坏掉, 导致数据不能备份成功。-解决方法找到 所有错误记录 删除 -监测错误记录的语法 beginset serveroutput onexec dbms_output.enable(100000);declarepag number;len number;c varchar2(10);charpp number := 8132/2;beginfor r in (select rowid rid, dbms_lob.getlength (ANNEX_CONTENT) lenfrom annex ) loo
15、pif r.len is not null thenfor page in 0.r.len/charpp loopbeginselect dbms_lob.substr (ANNEX_CONTENT, 1, 1+ (page * charpp)into cfrom annex where rowid = r.rid;exceptionwhen others thendbms_output.put_line (Error on rowid |R.rid| page |page);dbms_output.put_line (sqlerrm);end;end loop;end if;end loop;end;-监测错误记录的语法 END