CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  Oracle >  基础和管理

ORA-01555: 快照过旧: 回退段号 4 在名称为 "_SYSSMU4$" 过小

楼主tonytyk()2005-03-07 13:50:54 在 Oracle / 基础和管理 提问

我用java做的开发,表中数据比较多,几万条吧,当执行到一定程度时候,就出此错误。我已经知道要增加回退段,但是我不知道具体该怎么做,如何将此大事务指定到此回退段?请具体给一个例子好吗。要一步一步的写清楚,我知道写一点java程序,对此一点也不清楚,只能照葫芦画瓢。谢谢了 问题点数:100、回复次数:21Top

1 楼tomhuang(春城)回复于 2005-03-07 13:54:44 得分 0

回滚段太小,你的数据库版本是??Top

2 楼tomhuang(春城)回复于 2005-03-07 13:55:45 得分 0

好像是set   resegment...Top

3 楼kerisyml(魂之利刃)回复于 2005-03-07 14:09:14 得分 0

ORA_01555   snapshot   too   old:   rollback   segment   number   string   with   name   "string"   too   small  
  原因可分为以下情形:  
  A.   回滚段太少/太小  
  数据库中有太多的事务修改数据并提交,   就会发生已提交事务曾使用的空间被重用,   从而造成一个延  
   
  续时间长的查询所请求的数据已经不在回滚段中.  
  解决方法:   创建更多的回滚段,   为回滚段设置较大的EXTENT以及较大的MINEXTENTS  
   
  B.   回滚段被破坏  
  由于回滚段被破坏,   造成事务无法将修改前的内容(read-consistent   snapshot)   放入回滚段,   也会产生ORA-01555错误.  
  解决方法:   将被破坏的回滚段OFFLINE,   删除重建.  
   
  C.   FETCH   ACROSS   COMMIT  
  当一个进程打开一个CURSOR,   然后循环执行FETCH,   UPDATE,   COMMIT,   如果更新的表与FETCH的是同一个表,   就很可能发生ORA-01555错误.  
   
  解决方法:  
   
  a.   使用大的回滚段  
   
  b.   减少提交频率(可参见本论坛"如何避免一个PROCEDURE被重复调用"一贴中,   无名朋友的回帖)  
  以上两种方法只能减少该错误发生的可能,   不能完全避免.   如果要完全避免,   须从执行方法着手,   可以用以下两种方法:  
   
  c.   建立一个临时表,   存放要更新的表的查询列(如主键及相关的条件列),   从临时表FETCH,   更新原来的表.  
   
  d.   捕获ORA-01555错误,   关闭并重新打开CURSOR,   继续执行循环:  
  示例(示例程序的思路来源自ORACLE的UTLIP.SQL,   有兴趣的朋友可直接阅读该程序,   位置在RDBMS\ADMIN下,   程序很短,   容易读):  
   
  ____DECLARE  
  ____LAST_PK   NUMBER   :=   0;  
  ____V_THEROWID   ROWID;  
  ____CURSOR   C1   IS  
  ________SELECT   ROWID,   PK,   …  
  ________FROM   SMPLE  
  ________WHERE   PK   >   LAST_PK  
  ________AND   othercondition  
  ________ORDER   BY   PK;  
  ____BEGIN  
  ________OPEN   c_SOURCE;  
  ________LOOP  
  ____________BEGIN  
  ________________FETCH   C1   INTO   v_THEROWID,   v_PK;  
  ________________EXIT   WHEN   C1%NOTFOUND;  
  ____________EXCEPTION   WHEN   OTHERS   THEN  
  ________________IF   SQLCODE   =   -1555   THEN   --   snapshot   too   old,   re-execute   fetch   query  
  ____________________CLOSE   C1;  
  ____________________OPEN   c_SOURCE;  
  ____________________GOTO   NEXTLOOP01555;  
  ________________ELSE  
  ____________________RAISE;  
  ________________END   IF;  
  ____________END;  
  ____________LAST_PK   :=   PK;  
  ………   …   PROCESS,   UPDATE   AND   COMMIT  
  ____________<>  
  ____________NULL;  
  ________END   LOOP;  
  ________CLOSE   C1;  
  ____END;  
   
  D.   其它原因:  
  *   Delayed   logging   block   cleanout是ORACLE用来提高写性能的一种机制:   当修改操作(INSERT/UPDATE/DELETE)发生时,   ORACLE将原有的内容写入回滚段,   更新每个数据块的头部使其指向相应的回滚段,   当该操作被COMMIT时,   ORACLE并不再重新访问一遍所有的数据块来确认所有的修改,   而只是更新位于回滚段头部的事务槽来指明该事务已被COMMIT,   这使得写操作可以很快结束从而提高了性能接下来的任何访问该操作所修改的数据的操作会使先前的写操作真正生效,   从而访问到新的值.   Delayed   logging   block   cleanout   虽然提高了性能,   但却可能导致ORA-01555.   这种情况下,   在OPEN/FETCH前对该表做全表扫描(保证所有的修改被确认)会有所帮助.  
   
  *   不适当的OPTIMAL参数:   太小的OPTIMAL参数会使回滚段很快被SHRINK,   造成后续读取操作访问时,   先前的内容已丢失.   仔细设计OPTIMAL参数,   不要让回滚段过于频繁的EXTEND/SHRINK有助于问题的解决.  
   
  *   DB   BLOCK   BUFFER太小:   如果读一致性所请求的块的先前内容在缓冲区中,   那么就不用去访问回滚段.   而如果缓冲区太小,   使得先前版本的内容在CACHE中的可能性变小,   从而必须频繁的访问回滚段来获取先前的内容,   这将大大增大ORA-01555发生的可能.Top

4 楼NinGoo(http://www.NinGoo.net)回复于 2005-03-07 14:09:18 得分 0

参考:  
   
   
  ORA-01555:snapshot   too   old   (rollback   segment   too   small)    
   
  ----   这说明   oracle   给此事务随机分配的回滚段太小了   ,   这时可以为它指定一个足够大的回滚段   ,   以确保这个事务的成功执行   .   例如    
   
  set   transaction   use   rollback   segment   roll_abc;    
   
  delete   from   table_name   where   ...    
   
  commit;    
   
  ----   回滚段   roll_abc   被指定给这个   delete   事务   ,commit   命令则在事务结束之后取消了回滚段的指定   .    
   
  Top

5 楼tonytyk()回复于 2005-03-07 14:13:54 得分 0

楼上的,你这个我看过了,但是我不知道如何在java程序中指定。我是先选择数据,然后循环对每一行进行操作。在java社区提了这个问题,一个回复都没有。Top

6 楼kerisyml(魂之利刃)回复于 2005-03-07 14:16:05 得分 20

ORA_01555   snapshot   too   old:   rollback   segment   number   string   with   name   "string"   too   small  
  原因可分为以下情形:  
  A.   回滚段太少/太小  
  数据库中有太多的事务修改数据并提交,   就会发生已提交事务曾使用的空间被重用,   从而造成一个延  
   
  续时间长的查询所请求的数据已经不在回滚段中.  
  解决方法:   创建更多的回滚段,   为回滚段设置较大的EXTENT以及较大的MINEXTENTS  
   
  B.   回滚段被破坏  
  由于回滚段被破坏,   造成事务无法将修改前的内容(read-consistent   snapshot)   放入回滚段,   也会产生ORA-01555错误.  
  解决方法:   将被破坏的回滚段OFFLINE,   删除重建.  
   
  C.   FETCH   ACROSS   COMMIT  
  当一个进程打开一个CURSOR,   然后循环执行FETCH,   UPDATE,   COMMIT,   如果更新的表与FETCH的是同一个表,   就很可能发生ORA-01555错误.  
   
  解决方法:  
   
  a.   使用大的回滚段  
   
  b.   减少提交频率(可参见本论坛"如何避免一个PROCEDURE被重复调用"一贴中,   无名朋友的回帖)  
  以上两种方法只能减少该错误发生的可能,   不能完全避免.   如果要完全避免,   须从执行方法着手,   可以用以下两种方法:  
   
  c.   建立一个临时表,   存放要更新的表的查询列(如主键及相关的条件列),   从临时表FETCH,   更新原来的表.  
   
  d.   捕获ORA-01555错误,   关闭并重新打开CURSOR,   继续执行循环:  
  示例(示例程序的思路来源自ORACLE的UTLIP.SQL,   有兴趣的朋友可直接阅读该程序,   位置在RDBMS\ADMIN下,   程序很短,   容易读):  
   
  ____DECLARE  
  ____LAST_PK   NUMBER   :=   0;  
  ____V_THEROWID   ROWID;  
  ____CURSOR   C1   IS  
  ________SELECT   ROWID,   PK,   …  
  ________FROM   SMPLE  
  ________WHERE   PK   >   LAST_PK  
  ________AND   othercondition  
  ________ORDER   BY   PK;  
  ____BEGIN  
  ________OPEN   c_SOURCE;  
  ________LOOP  
  ____________BEGIN  
  ________________FETCH   C1   INTO   v_THEROWID,   v_PK;  
  ________________EXIT   WHEN   C1%NOTFOUND;  
  ____________EXCEPTION   WHEN   OTHERS   THEN  
  ________________IF   SQLCODE   =   -1555   THEN   --   snapshot   too   old,   re-execute   fetch   query  
  ____________________CLOSE   C1;  
  ____________________OPEN   c_SOURCE;  
  ____________________GOTO   NEXTLOOP01555;  
  ________________ELSE  
  ____________________RAISE;  
  ________________END   IF;  
  ____________END;  
  ____________LAST_PK   :=   PK;  
  ………   …   PROCESS,   UPDATE   AND   COMMIT  
  ____________<>  
  ____________NULL;  
  ________END   LOOP;  
  ________CLOSE   C1;  
  ____END;  
   
  D.   其它原因:  
  *   Delayed   logging   block   cleanout是ORACLE用来提高写性能的一种机制:   当修改操作(INSERT/UPDATE/DELETE)发生时,   ORACLE将原有的内容写入回滚段,   更新每个数据块的头部使其指向相应的回滚段,   当该操作被COMMIT时,   ORACLE并不再重新访问一遍所有的数据块来确认所有的修改,   而只是更新位于回滚段头部的事务槽来指明该事务已被COMMIT,   这使得写操作可以很快结束从而提高了性能接下来的任何访问该操作所修改的数据的操作会使先前的写操作真正生效,   从而访问到新的值.   Delayed   logging   block   cleanout   虽然提高了性能,   但却可能导致ORA-01555.   这种情况下,   在OPEN/FETCH前对该表做全表扫描(保证所有的修改被确认)会有所帮助.  
   
  *   不适当的OPTIMAL参数:   太小的OPTIMAL参数会使回滚段很快被SHRINK,   造成后续读取操作访问时,   先前的内容已丢失.   仔细设计OPTIMAL参数,   不要让回滚段过于频繁的EXTEND/SHRINK有助于问题的解决.  
   
  *   DB   BLOCK   BUFFER太小:   如果读一致性所请求的块的先前内容在缓冲区中,   那么就不用去访问回滚段.   而如果缓冲区太小,   使得先前版本的内容在CACHE中的可能性变小,   从而必须频繁的访问回滚段来获取先前的内容,   这将大大增大ORA-01555发生的可能.Top

7 楼libin_ftsafe(子陌红尘:TS for Banking Card)回复于 2005-03-07 14:32:38 得分 0

增大回滚段的大小。Top

8 楼tonytyk()回复于 2005-03-07 15:07:04 得分 0

我的程序大概是这样  
  PreparedStatement   pStmt   =   conn.prepareStatement("select   *   from   table");  
  ResultSet   rst   =   pStmt.executeQuery();  
  while(rst.next())  
  {  
      do   something;  
   
  }Top

9 楼tonytyk()回复于 2005-03-07 15:10:48 得分 0

我的程序大概是这样      
  PreparedStatement     pStmt     =     conn.prepareStatement(     "select     *     from     table     ");      
  ResultSet     rst     =     pStmt.executeQuery();      
  while(rst.next())      
  {      
        do     something;      
        ...  
        在这里更新相应行;  
  }    
  在程序中可以指定到某一回退段吗  
  Top

10 楼nebulaly(极高明而道中庸)回复于 2005-03-07 17:42:55 得分 0

增加回滚段大小无用,增加回滚段个数可能有用  
   
  在循环中commit的典型问题Top

11 楼tonytyk()回复于 2005-03-08 08:47:13 得分 0

楼上能说的具体点吗,拜托了Top

12 楼yujiabian(流氓兔子雨)回复于 2005-03-08 09:43:52 得分 0

ORA-01555   snapshot   too   old:   rollback   segment   number   string   with   name   "string"   too   small      
   
  Cause   Rollback   records   needed   by   a   reader   for   consistent   read   are   overwritten   by   other   writers.      
  Action   Use   larger   rollback   segments.      
  Top

13 楼nebulaly(极高明而道中庸)回复于 2005-03-08 13:38:14 得分 10

这个问题涉及ORACLE的事务处理实现方式  
  楼主可以简单的理解为:在执行长查询的同时频繁commit,回滚段被重用,  
  查询读不到其中保存的数据前象,就会出现01555错误Top

14 楼nebulaly(极高明而道中庸)回复于 2005-03-08 13:41:24 得分 10

由于commit之后,事务结束  
  下一条DML会选择一个空闲的回滚段使用,  
  由于频繁commit,事务的数据量很小  
  所以增加回滚段个数有用,增加会滚段尺寸无用Top

15 楼tonytyk()回复于 2005-03-09 09:38:44 得分 0

各位,我不是数据库管理员,对Oracle也不是很熟悉。我用的Oracle版本是9i,我建立一个新回滚段时提示我自动提交模式下的非法操作,我改了init.ora文件将提交模式设置为手动了,但是只能在系统空间中建回滚段,我是不是应该在表所在的空间建立回滚段才有效呢。我是不是应该把提交模式改回到自动模式?增加回滚段个数之后系统就会自动调用吗,还是要我自己指定呢?我是在程序中写的SQL语句,而且不能把这个事务写成过程,这里有哪位好心的高人多多指点一下。Top

16 楼nebulaly(极高明而道中庸)回复于 2005-03-09 13:01:59 得分 0

解决办法很简单:不要在循环中commit,也就是采用手动提交模式,在循环外面commit  
   
  btw:为回滚段建立单独的表空间,否则存在很大隐患Top

17 楼hippie1024(努力必有痕迹)回复于 2005-03-09 13:46:01 得分 30

看你回滚段名字就能看出是9i的自动回滚段空间管理了。  
  1.你可以把参数undo_tablespace中设置的undo表空间加大  
  2.同时如果你的查询时间超过undo_retention的设置也会发生,可以加大它  
  3.9i前面的版本有些bug也会导致ORA-01555,考虑升级到9206Top

18 楼tonytyk()回复于 2005-03-10 09:04:39 得分 0

nebulaly(nebulaly):在循环外面提交?如果我提交的数据有很多的话这样做可以吗?  
  这么多种说法我该听谁的?Top

19 楼epicurus()回复于 2005-03-10 11:25:56 得分 30

一是建个较大回滚段,一定要重建,要用更大的存储参数,仅修改MAXEXTENTS是没用的  
  二是这个回滚段要位于非系统的表空间上  
  三是set   resegment为该事务指定用这个较大的回滚段Top

20 楼nebulaly(极高明而道中庸)回复于 2005-03-10 12:29:37 得分 0

如果数据量大,可以手动指定回滚段  
   
  但一般没有必要Top

21 楼tonytyk()回复于 2005-03-11 09:12:30 得分 0

失望Top

相关问题

  • 快照?
  • 快照
  • 快照错误!!!!
  • 页面回退的问题?
  • IE回退按钮(back)?
  • 如何建立回退段
  • 浏览器回退问题
  • 回退段??(在线等)
  • 回退符怎么输入?
  • 可修改快照(updateable)

关键词

  • 数据
  • 修改
  • 循环
  • 执行
  • 查询
  • 解决
  • 回滚段
  • 表
  • 事务
  • 回退

得分解答快速导航

  • 帖主:tonytyk
  • kerisyml
  • nebulaly
  • nebulaly
  • hippie1024
  • epicurus

相关链接

  • Oracle类图书

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo