紧接上篇:http://www.ixdba.net/article/35/1458.html
1555错误发生的情况
下面我们就模拟一下1555错误发生的情况。
测试环境
首先建立测试环境。由于我们只是要模拟1555错误的发生,所以需要建立一个小的回滚表空间,并且设置undo_retention时间为1(秒),以便回滚数据尽快被覆盖(呵呵,要防止1555错误发生,这就一定要避免的)。
CREATE UNDO TABLESPACE rbs_ts
DATAFILE 'rbs_ts2.dbf' SIZE 10M AUTOEXTEND OFF;
alter system set undo_retention=1 scope=spfile;
alter system set undo_management=auto scope=spfile;
alter system set undo_tablespace=rbs_ts scope=spfile;
startup force
alter tablespace rbs_ts online;
create table demo.t_dual as select * from dual;
www.ixdba.net
insert into t_dual values(1);
commit;
一致性读导致的1555错误
开始读取表。
SQL>
SQL> var cl refcursor
SQL> begin
2 open :cl for select * from demo.t_multiver;
3 end;
4 /
PL/SQL procedure successfully completed.
SQL>
更新表数据,产生回滚信息。
SQL> update demo.t_multiver set b = 111 where a = 1;
1 row updated.
SQL> commit;
Commit complete.
运行大批其他事务,充满所有回滚段,以致覆盖上面的回滚信息。回滚段可以通过dba_rollback_segs查看。
SQL> begin
2 for i in 1..20000 loop
3 update demo.t_dual set dummy=1;
4 commit;
5 end loop;
6 end;
7
8 /
PL/SQL procedure successfully completed.
SQL> /
PL/SQL procedure successfully completed.
查询到更新过的数据记录,回滚信息已经被覆盖,所以报1555错误。
SQL> print :cl
ERROR:
ORA-01555: snapshot too old: rollback segment number 18 with name "_SYSSMU18$"
too small
no rows selected
SQL>
延迟块清除导致的1555错误
开始读取表。
SQL> var cc refcursor
SQL>
SQL> begin
2 open :cc for select * from t_multiver;
3 end;
4 /
这时一个事务更新了该数据块,但在提交前,我们手工将buffer cache中的数据做了flush,再做提交。这时的数据块上只记录了锁标志,没有事务标志和Commit SCN。
PL/SQL procedure successfully completed.
SQL>
SQL> update t_multiver set b=115 where a=1;
1 row updated.
SQL>
SQL> alter system flush buffer_cache;