在 Oracle 中数据锁(这里主要指 TX 类型行锁)实际上是数据的属性,存储在块首部,称之为事务槽 (ITL) 。
COMMIT 操作的职责包括释放块上的锁,实际的释放方式即清除块上相应的事务槽,但这里存在一个性能的考量:
设想一个 UPDATE 大量数据的操作,因为执行时间较长, 一部分已修改的块已被缓冲池 flush out 写至磁盘 ,当 UPDATE 操作完成执行 COMMIT 操作时,则需要将那些已写至磁盘的数据块重新读入,这将消耗大量 I/O ,并使 COMMIT 操作十分缓慢。
下面说说关于上面那句话的理解:
假设有 100 个块在进行 update ,但是还没有进行 commit 操作,由于 buffer cache 快被占满了,就先将前 20 个块从缓冲池写到了磁盘 ( 对应一 部分已修改的块已被缓冲池 flush out 写至磁盘 ) ,此时这 20 个块的记录的状态信息是不对的还是未 commit ,因此在真正 commit 期间,还需要将这些状态信息不对的块重新读入到 buffer cache 里进行状态信息的修改 ( 对应 需要将那些已写至磁盘的数据块重新读入 ) ,因此会造成许多无用的 I/O ,而且使得 commit 缓慢。
因此伟大的 Or acle 在这里引入了延迟段清理的概念 ( 40689.1) 。
它留给访问受更新影响的任何块的下一个事务 (select 、 update 、 delete 、 insert 都可以 ) 来 “ 整理 ” 该块,也就是修改块的状态信息(因此称为 “ 延迟块清理 ” )。
对待存在以下情况的块 COMMIT 操作不做块清除 ( 而是转为延迟清除 ) :
|
1
2 |
1、在更新过程中,被缓冲池flush
|
块延迟清除通过事务槽上的回滚段号,槽号等信息访问回滚段头的事务字典,若事务不再活跃或事务过期则完成清除块上的事务槽,事务槽清除后继续执行相应的操作。
总结来说块延迟清除是 COMMIT 操作的一个延续,始终是一种十分轻微的操作,且该种操作是行级的,不会使段 (Segment) 的属性有所改变。
块延迟清除的影响在 SELECT 操作过程中体现的最为明显。在 select 时若发生了延迟块清除,就会去修改块的状态信息, 因此会产生 redo 。
