在大型OLAP系统中运行查询经常会遭遇“ORA-01555: snapshot too old”的错误。这是因为Oracle为了保持读一致性,需要从回滚段中读取被修改的记录,但是同时这条被修改的记录在回滚段中却找不到了。这时,就会报错“ORA-01555: snapshot too old”。实验思路:
1. 创建大小为1M的回滚段,并让系统指定使用它。
2. 创建一个游标cur,让它查询表TA,但是先不打印,如下的session_1_test3。
3. 更新表TA中的第二行,并且提交,如下的session_2_test3。
4. 刷新SGA中的高速数据缓存,使得回滚段空间全部为可用,如下的session_3_sysdba。
5. 频繁的更新某一个表,确保回滚段中的空间全部被覆盖,意即找不到步骤3中被更新的记录,如下的session_4_test3。
6. 在步骤2中的session中打印游标cur。

步骤1

 
  
  1. SQL> conn / as sysdba; 
  2. 已连接。 
  3. SQL> create undo tablespace UNDOTBS4 datafile 'D:\ORACLE TABLESPACES\UNDOTBS04_1.DBF' size 1M autoextend off
  4.   
  5. Tablespace created 
  6.  
  7. SQL> alter system set undo_tablespace = UNDOTBS4 scope = both; 
  8.   
  9. System altered 
  10.  
  11. SQL> alter system set undo_retention=1 scope = both; 
  12.   
  13. System altered 
  14.  
  15. SQL> column name format a20  
  16. SQL> column display_value format a20  
  17. SQL> select name, display_value from v$parameter where name like 'undo%'
  18.  
  19. NAME                 DISPLAY_VALUE 
  20. -------------------- -------------------- 
  21. undo_management      AUTO 
  22. undo_tablespace      UNDOTBS4 
  23. undo_retention       1 
  24.  
  25. SQL> select tablespace_name, RETENTION from dba_tablespaces where tablespace_name = 'UNDOTBS4'
  26.   
  27. TABLESPACE_NAME                RETENTION 
  28. ------------------------------ ----------- 
  29. UNDOTBS4                       NOGUARANTEE 
  30.  
  31. SQL> create user test3 identified by test3; 
  32.   
  33. User created 
  34.   
  35. SQL> grant connect, resource to test3; 
  36.   
  37. Grant succeeded 
  38.   
  39. SQL>  

步骤2

 
  
  1. SQL> conn test3/test3; 
  2. 已连接。 
  3. SQL> set sqlprompt 'session_1_test3> '
  4. session_1_test3> create table TA (a number, b varchar2(20)); 
  5.  
  6. 表已创建。 
  7.  
  8. session_1_test3> insert into TA (a, b) values(1, 'a'); 
  9.  
  10. 已创建 1 行。 
  11.  
  12. session_1_test3> insert into TA (a, b) values(2, 'b'); 
  13.  
  14. 已创建 1 行。 
  15.  
  16. session_1_test3> commit
  17.  
  18. 提交完成。 
  19.  
  20. session_1_test3> var cur refcursor; 
  21. session_1_test3> begin 
  22.   2  open :cur for select * from TA; 
  23.   3  end
  24.   4  / 
  25.  
  26. PL/SQL 过程已成功完成。 
  27.  
  28. session_1_test3> 

步骤3

 
  
  1. SQL> conn test3/test3 
  2. 已连接。 
  3. SQL> set sqlprompt 'session_2_test3'
  4. session_2_test3> update TA set b = 'c' where a = 2; 
  5.  
  6. 已更新 1 行。 
  7.  
  8. session_2_test3> commit
  9.  
  10. 提交完成。 
  11.  
  12. session_2_test3> 

步骤4

 
  
  1. SQL> conn / as sysdba 
  2. 已连接。 
  3. SQL> set sqlprompt 'session_3_sysdba >'
  4. session_3_sysdba >--The FLUSH BUFFER_CACHE clause lets you clear all data from the buffer cache in the system global area (SGA). 
  5. session_3_sysdba >alter system flush buffer_cache; 
  6.  
  7. 系统已更改。 
  8.  
  9. session_3_sysdba > 

步骤5

 
  
  1. session_4_test3> create table testa as select * from dual; 
  2.  
  3. 表已创建。 
  4.  
  5. session_4_test3> begin 
  6.   2  for i in 1..10000 loop 
  7.   3  update testa set dummy = 'A'
  8.   4  commit
  9.   5  end loop; 
  10.   6  end
  11.   7  / 
  12.  
  13. PL/SQL 过程已成功完成。 
  14.  
  15. session_4_test3> 

步骤6

 
  
  1. session_1_test3> print cur; 
  2. ERROR: 
  3. ORA-01555: 快照过旧: 回退段号 29 (名称为 "_SYSSMU29$") 过小 
  4.  
  5.  
  6.  
  7. 未选定行 
  8.  
  9. session_1_test3> 

备注:
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: If in Automatic Undo Management mode, increase undo_retention setting. Otherwise, use larger rollback segments