快照太旧

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发生的可能.

posted @ 2013-12-05 15:54  bj_google  阅读(443)  评论(0编辑  收藏  举报