日期:2014-05-16 浏览次数:20492 次
oracle在读的过程中,数据是静止的,没有脏读,也就是,未提交的永远都不会被读到。我们可以理解为,oracle在读的开始时,提前为他今后所要读的内容拍了一张”照片“,把所有内容全部定格在一个时间点上,作为接下来读的依据。oracle利用scn来实现这个理论,开始查询时,会确定一个select scn,这样就保证了事务槽里所有的scn都小于select scn。好比如,现在是12:21分,那么我之前所敲的字都在12:21分之前做的。
我们已经知道,undo段是循环使用,并且,oracle只会把inactive的事务给覆盖。若是一个长时间的查询需要读到被覆盖的块时,就会报ora-01555错误。借助v$undostat里面的字段ssolderrcnt来查询在每个10分钟,oracle内是否发生过01555错误。
下面是一张01555错误的图:
产生01555错误,原因有好多,这里列三个:
1)undo_retention不够大
2)undo空间压力大
3)sql性能差
下面我们来模拟01555错误。注意,这里要避免和30036错误相混淆。
会话1:
hr@ORCL> var i refcursor hr@ORCL> exec open :i for select * from t; PL/SQL procedure successfully completed. hr@ORCL> print i; ID NAME ---------- ---------- 1 a 2 b hr@ORCL> exec open :i for select * from t; PL/SQL procedure successfully completed.
会话2:
sys@ORCL> delete from hr.t; 3 rows deleted. sys@ORCL> commit; Commit complete.
会话1:
hr@ORCL> print i; ID NAME ---------- ---------- 1 a 2 b
如果有数据,则证明查询是修改前的;如果没有数据,则证明查询是修改后的。但如果,此时undo里面没有数据,那就会报错。从查询输出,可知,查询是修改前的。
会话2:
sys@ORCL> create undo tablespace undotbs2 datafile '/u01/app/oracle/oradata/ORCL/datafile/undotbsthi.dbf' size 1m autoextend off; Tablespace created. sys@ORCL> alter system set undo_tablespace=undotbs2; System altered. sys@ORCL> show parameter undo_tablespace NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ undo_tablespace string UNDOTBS2
会话1:
hr@ORCL> select * from t; no rows selected hr@ORCL> insert into t values (1,'a'); 1 row created. hr@ORCL> insert into t values(2,'b'); 1 row created. hr@ORCL> insert into t values(3,'c'); 1 row created. hr@ORCL> select * from t; ID NAME ---------- ---------- 1 a 2 b 3 c hr@ORCL> commit; Commit complete. hr@ORCL> exec open :i for select * from t; PL/SQL procedure successfully completed.
会话2:
sys@ORCL> select a.spid "专用服务器进程",b.process "客户进程" from v$process a,v$session b where a.addr=b.paddr and b.sid=(select sid from v$mystat where rownum=1) 2 3 4 5 ; 专用服务器进 客户进程 ------------ ------------ 8427 8425 sys@ORCL> declare i number :=0; begin loop update hr.t set id=i; i:=i+1; if mod(i,200)=0 then commit; end if; end loop; end;
会话1:
hr@ORCL> print i; ERROR: ORA-01555: snapshot too old: rollback segment number 11 with name "_SYSSMU11$" too small
会话3:
[root@