Oracle block cleanout
转自 http://blog.csdn.net/zengmuansha/article/details/8601663
简单点说,在oracle的block上都有活动事务的标志的,如果一个事务commit后,由于某些block在commit之前已经写回datafile,或者事务影响到的block数过多,则commit的时候只会清理undo segment header中的事务表信息,data block上的事务标志不会清除,在否则代价过高。那么在一些读取这些block时,需要将这些事务标志进行清除,就是延迟块清除
块清除即清除数据块上与“锁定”有关的信息。Oracle的锁机制是一种轻量级的锁定机制,不是通过构建锁列表来进行数据的锁定管理,而是直接将锁作为数据的属性,存储在数据块首部。因此,每次访问数据时都要去看数据块头部的锁,如果数据已经提交,则可能需要清理这个块,换句话说,要将这些事务信息删除。因此这个动作就会生成redo。
Cleanout有2种,一种是fast commit cleanout(提交清除),另一种是delayed block cleanout(延迟清除).
提交清楚是如何工作的?Oracle会记录已修改的块列表,这些列表可以有20个块,Oracle根据需要分配多个这样的列表,但是如果这些修改的块加起来超过buffer_cache的10%,oracle就停止分配这样的列表,因此当提交时就只会清理最多10%buffer_cache的数据块,其余的部分就延迟清除,这样也是为了提高commit的效率。
还有一种情况,就是当事务还未commit时,修改的数据块已经写入硬盘,当发生commit时oracle并不会把block重新读入做cleanout,而是把cleanout留到下一次对此块的访问是完成。
Cleanout有2种,一种是fast commit cleanout,
另一种是delayed block cleanout.Oracle的每个事务(transaction)修改不超过10%buffer cache的数据块时,oracle做的是fast commit cleanout。如果一个事务(transaction)修改的块超过10% buffer cache,那么超过的块就执行delayed block cleanout,还有一种情况,就是当事务还未commit时,修改的数据块已经写入硬盘,当发生commit时oracle并不会把block重新读入做cleanout,而是把cleanout留到下一次对此块的访问是完成。
当我们update 数据之后,并且没有commit,此时我们flush buffer cache,将修改的数据块,flush 到硬盘,那么此时发生的就是delay block cleanout
正常情况下,会去修改block里的相关SCN。 但是实际上此时Oracle 并没有回去修改这些block,因为再次调用成本太大。 Oracle只更新了undo segment header slot。 当下次再次访问这个block时,在根据undo segment 来更新block scn 和 itl 上的scn。 如果此时对应的undo segment 已经不存在,就会出发ORA-01555,快照过旧的错误。
做了delayed block cleanout之后,itl 变成了SCN。 此时lck,lb标志为都被清零,scn也是从undo segment header transactiontable slot里面得到。如果undosegment header 上的slot被覆盖了,那么会把undo segment 上的control scn拿来当作upper bound scn
当delayed block cleanout 发生时,依赖与undo segment来保证,如果undo segment 被删除了,那么会Oracle 会使用system 表空间下的undo$ 基表来保证delayed block cleanout。
一般来说,select 是不会产生redo的。 但如果发生了delayed block cleanout,那么就会产生redo。 当然这只是一种情况,开启审计等,也会造成select 产生redo