block cleanout

没想到在执行select的时候也有可能生产redo 信息。

lock存储在block header中。lock的一个副作用是:在下一次access这个block的时候,需要清除lock信息,也就是清除transaction 信息。这个动作会生成redo,并使不是dirty block变成dirty block。也是因为这样,一个简单的select也可能生成redo,并导致在下一个checkpoint发生时,有大量的block需要写入到磁盘上。所幸,这样的事情并不是经常发生的。

之前在http://zzwssfd.iteye.com/blog/1560112 中有说到commit后,系统会revisit那些依然在SGA中,且可以access的blocks。然后清除blocks中的locks。这样使用COMMIT就可以清除那些lock,而不用稍后在SELECT 的时候去清除。

我们可以强制的使“清除”动作不发生,来看看这样做的效果如何。有一个commit list是和用户的transaction相关的,oracle会在commit list中记录用户修改过的blocks。每一个commit list是20个blocks长,oracle会维护这些list直到这些blocks的总和(SUM值)超过block buffer cache size的10%后,不再分配新的blocks给commit lists。例如,用户的buffer cache是3000个blocks,oracle最多维护300个blocks的commit list。 在commit时,oracle会对每20个可用的blocks执行一次“清除”动作。只有用户修改的blocks没有超过buffer cache的10%,切那些修改后的blocks依然在buffer cache中,切依然可用,oracle都会执行“清除”。

下面用例子来验证"清除“(cleanout)的发生。

1,disable SGA的automatic management 功能

2,设置DB_CACHE_SIZE等于16MB。这样buffer cache可以容纳2048个blocks(每个block是8K)。

3,创建一个一行占用一个block的表。向表中插入10000行数据,commit。这样就有10000个blocks被修改,超     过了buffer cache的10%。因此数据库不足以通过commit来清除所有的blocks的locks信息。事实上,大部分     的数据已经不再buffer cache中了。

4,收集redo生成的信息

5,执行一次SELECT



 这里执行了一个DBMS_STATS,是为了在hard parsing的时候产生副作用。



 下面就是收集redo信息:


上图中执行了两次SELECT。第一次SELECT产生了721652 bytes的redo信息。第二次SELECT 没有产生redo信息。这是因为第一次SELECT的时候,oracle并未对所有修改过的10000个blocks都进行”清除“,只是清除了一部分。因为我们修改了10000个blocks,这超过了oracle可以维护的最大的commit list值。所有在第一次SELECT的时候会有redo生成。第二次SELECT的时候,由于第一次的SELECT 已经完成了”清除“工作,所有没有redo生成。

以上来自TOM的《Expert Oracle Database Architecture Oracle Database Programming 9i, 10g, and 11g Techniques and Solutions, Second Edition》

猜你喜欢

转载自zzwssfd.iteye.com/blog/1563197