有时候我们在执行select操作的时候也可能会产生redo,其一个可能原因就是oracle块清除。

在进行块清除的时候,如果是一个大事务,就会进行延迟块清除块清除就是删除所修改数据块上与”锁定”有关的信息,即事务信息

Oracle在事务相关的提交列表中,记录下已修改的块列表,每个列表记录20个块,根据需要可能分配有多个这种列表.
这种块列表有一个上限,就是缓冲区缓存大小的10%.
如果一次修改的块,没有超过了缓冲区缓存大小的10%,并且这些块在内存中,则commit时,会清除块上的事务信息,
否则,就不会理会它,直到下次访问这些块时,再清除块中的事务信息,这就是延迟块清除.
因为这个Select修改了块的事务信息,所以就会产生Redo.

关于块清除时SCN的填写,以及什么情况产生”快照太旧”的错误:
延迟清除的块的下一个读者,首先根据块中的记录的回滚信息去查找回滚段中记录的commit时的SCN,
但回滚段可能已回绕,找不到提交时的scn了,
但是,从回滚段中可以得到一个最小的提交scn并且该事务已经提交肯定小于这个从回滚段中还存在的最小scn。
那么oracle给这个块清除的事务分配一个从回滚段中找到的最小事务scn。
这虽然不准确,但是是安全的,对于数据访问也不构成影响。所以叫 upper bound ,猜测的一个scn的上限。

延迟清除的块在被select 时,如果读的select 的scn 比这个回滚段里面最小的scn 还要小的话(回滚段已回绕),那么在回滚段里面找不到数据了,oracle 就没有办法判断select 的SCN 与被要清除的数据块的大小关系,于是ora-01555就出现了,这个时候oracle 就不知道数据块里面的数据是不是是查询时刻需要的数据.

如果select scn 大于回滚段里面最小的scn 的话,那么oracle 就使用这个最小的scn 来做为这个事务的 scn 来更新块的itl ,从而完成块的清除.


除了本文文中方法,还有一种方法:

非IMU模式下可测:会话1:修改      会话2:做完全检查点 alter system checkpoint;      清空数据缓存区alter system flush buffer_caache;     再查询


实验一:延迟块清除的产生


1.先构建一个1万条数据的表


create table test as select * from dba_objects where rownum<10001;



2.使用循环来插入数据。


初始数据1W条,则每次循环后表内数据量依次是2,4 ,8 ,16 ,32 ,64 ,128, 256,512,1024,需要10次循环。


begin

 for i in 1 .. 10 loop

 insert into test select * from test;

   commit;

 end loop;

   end;


3.执行查询,执行计划中可以看到      

2204  redo size

 SQL> select count(*) from test;

   COUNT(*)

 ----------

    5120000

 SQL> select count(1) from dba_indexes where  table_name='TEST';

   COUNT(1)

 ----------

          0

 SQL> alter system flush buffer_cache;

 System altered.

 SQL> set autotrace on

 SQL> select count(*) from test where object_name like '%gc%';

   COUNT(*)

 ----------

          0

 Execution Plan

 ----------------------------------------------------------

 Plan hash value: 1950795681

 ---------------------------------------------------------------------------

 | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |

 ---------------------------------------------------------------------------

 |   0 | SELECT STATEMENT   |      |     1 |    66 | 18588   (1)| 00:03:44 |

 |   1 |  SORT AGGREGATE    |      |     1 |    66 |           |   |

 |*  2 |   TABLE ACCESS FULL| TEST |   751 | 49566 | 18588   (1)| 00:03:44 |

 ---------------------------------------------------------------------------

 Predicate Information (identified by operation id):

 ---------------------------------------------------

    2 - filter("OBJECT_NAME" IS NOT NULL AND "OBJECT_NAME" LIKE '%gc%')

 Note

 -----

    - dynamic sampling used for this statement (level=2)

 Statistics

 ----------------------------------------------------------

           5  recursive calls

           0  db block gets

      101073  consistent gets

       67716  physical reads

     
   2204  redo size

         421  bytes sent via SQL*Net to client

         419  bytes received via SQL*Net from client

           2  SQL*Net roundtrips to/from client

           0  sorts (memory)

           0  sorts (disk)

         1  rows processed


实验二:延迟块清除的避免


因为延迟块清除有可能会导致ORA-01555错误(操作大数据时),所以应该避免。


在操作大数据量的DML操作后做一个select 操作。


SQL> create table test as select * from dba_objects where rownum<10001;

 Table created.

 SQL> 

 declare

 v_select clob;

 begin

 for i in 1 .. 5 loop

 insert into test select * from test;

   commit;

 select count(*) into v_select from test;

 end loop;

   9    end;

 10  /


 PL/SQL procedure successfully completed.

 SQL> set autotrace on;

 SQL> alter system flush buffer_cache;

 System altered.



从查询结果中可以看到,  0  redo size,没有产生REDO。


SQL> select count(*) from test where object_name like '%gc%';

   COUNT(*)

 ----------

          0

 Execution Plan

 ----------------------------------------------------------

 Plan hash value: 1950795681


 ---------------------------------------------------------------------------

 | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |

 ---------------------------------------------------------------------------

 |   0 | SELECT STATEMENT   |      |     1 |    66 |  1134   (1)| 00:00:14 |

 |   1 |  SORT AGGREGATE    |      |     1 |    66 |           |   |

 |*  2 |   TABLE ACCESS FULL| TEST |    46 |  3036 |  1134   (1)| 00:00:14 |

 ---------------------------------------------------------------------------

 Predicate Information (identified by operation id):

 ---------------------------------------------------

    2 - filter("OBJECT_NAME" IS NOT NULL AND "OBJECT_NAME" LIKE '%gc%')

 Note

 -----

    - dynamic sampling used for this statement (level=2)

 Statistics

 ----------------------------------------------------------

           5  recursive calls

           0  db block gets

        4212  consistent gets

        4363  physical reads

         
  0  redo size
         421  bytes sent via SQL*Net to client

         419  bytes received via SQL*Net from client

           2  SQL*Net roundtrips to/from client

           0  sorts (memory)

           0  sorts (disk)

           1  rows processed