在讨论块清除算法之前,我们有必要来了解一下RBS的概念以及数据块和Transaction表的构造。
RBS:
RBS是记录Transaction回滚信息的领域。一个RBS可以被复数个Transaction使用, 但是一个Transaction只能使用一个RBS。即使这个RBS的容量不足,也不能中途改换成其它RBS使用。RBS的数量是有限的,当容量不足时,RBS会被循环利用。
在RBS的头块(Header block)上存在Transaction表。Transaction表里记录了Transaction 的commit的状态,以及Transaction的一些信息。
Transaction表:
:*Transaction表表头
:*Transaction表 - 使用这个RBS的Transaction的信息
: Slot1: Status, Transaction使用过的RBS的信息
: Slot2: 同上
在Transaction表的各Slot当中存有Transaction ID和这个Transaction使用过的RBS的位置信息。Transaction表的Slot只被一个Transaction使用。
Transaction表存在于RBS的头块(header block)当中。在表空间中被分配的Slot数也是有限的。Transaction如果commit的话,则与其对应的slot就变成可以被其它Transaction覆盖的状态。
数据块:
:*Header(块头)
:*ITL Entry(事物曹) - 记录对该数据块进行更新操作的Transaction的信息
: Entry1:Transaction ID, Flag(commit完成等), Commit SCN
: Entry2:同上
:*行数据 - 实际的数据,行锁信息
: Row 1: 行数据, 锁定该行的Transaction的ITL号
: Row 2: 同上
在变更的行当中,对该行进行变更的ITL号会被记录下来。
Transaction ID,是否已经commit,commit的SCN序列号等信息会被记录在ITL当中。根据Transaction ID 可以判断这个Transaction正在使用的RBS号和Slot号。
块清除
块清除有两种方法:fast commit clean out 和 delay block clean out
在Oracle中有数据回滚机制。当一个Transaction在commit发生异常时,被更新的数据块需要回滚到原来的状态,这就需要将数据块原来的信息记录到一个特定的表空间中以便回滚之用。
记录这个信息的表空间叫UNDO表空间。而获得数据块原来的行数据信息正是通过数据块中的ITL信息从UNDO表空间中获得的。
当一个数据块被一个Transaction更新后,这个数据块的ITL中的Flag会被更改成Active的状态,该行数据也会被锁定。而该Transaction在Transaction表的Slot中的状态也会被记录成Active,这时数据块里的状态与Slot里的状态是一致的。此时该数据块的相应行数据是没有办法被其它的Transaction进行读写操作。
Transaction执行commit操作时,Transaction表的Slot中的状态会被更改为commit完成状态, 同时,数据块的ITL中的Flag也会被更改成commit完成状态,并且去除行数据锁,并将最新的SCN记录在ITL当中。对数据块的这些操作被称为块清除。
fast commit clean out
Oracle数据库中,Transaction更改数据块的逻辑是:首先将磁盘上的数据块读取到buffer cache当中,然后更改这个数据块的行数据并将此数据块标记为脏块,放到脏块list当中,根据LRU算法,将脏块写到磁盘文件当中。
然而,buffer cache当中能够管理的数据块的个数是有限的。当一个Transaction更改大量的数据块时,buffer cache无法管理的行数据被更改过的一部分数据块会被写入磁盘中。因为此时Transaction没有执行commit操作,所以写入磁盘的数据块并没有被进行块清除处理。当Transaction执行commit操作后,在buffer cache中的数据块会被立刻进行块清除处理。这种块清除方式被称做fast commit clean out。
delay block clean out
我们都知道,当Transaction执行commit操作时,为了更改已经写入磁盘但还没有进行块清除的数据块的ITL信息,就必须要把该数据块从磁盘中再读入buffer cache中。可是这个读取操作会产生大量的I/O处理,而使数据库性能下降。为了提高Oracle的性能,Oracle导入了延迟块清除的概念。延迟块清除是指已经写入磁盘但还没有进行块清除的数据块不会被本次Transaction读到buffer cache中更改ITL信息。这样的数据块会被在下一次其它的Transaction读取时进行块清除处理。在下一次进行块读取的Transaction会根据这个数据块的ITL信息确认到这个数据块最后一次更新的Transaction ID,然后参照RBS中Transaction表信息,获取该Transaction的状态和commit的时间序列号从而更改数据块的ITL信息,进行块清除操作。