Chinaunix首页 | 论坛 | 博客
  • 博客访问: 403520
  • 博文数量: 127
  • 博客积分: 4025
  • 博客等级: 上校
  • 技术积分: 1980
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-18 18:09
文章分类

全部博文(127)

文章存档

2009年(127)

我的朋友

分类: Oracle

2009-09-06 21:08:36

2. log buffer的内部管理机制
日志缓冲区的内部管理分为两部分,一部分是重做记录的生成,另一部分就是重做记录写入联机日志
文件。这两部分不是孤立的,没有关联的。在生成重做记录的过程中,可能会触发LGWR将重做记录写入联机日志文件。
我们先用一个实例来说明在日志缓冲区中的操作过程,并使用[file# , blk#]来表示某个数据块,file#表示文件号,blk#表示数据块号。

假设session 1发出更新语句:update redo_test set name='cdf' where id=1;
Oracle 首先找出id=1所在的数据块(假设为[file#4,blk#120])放入buffer cache,然后找出一个可用的回滚段数据块(假设为[file#2,blk#19]),将旧值'abc'放入该块,同时生成重做记录。然后将'cdf' 放入表的数据块,再生成重做记录。这时的日志缓冲区的结构类似如下。(我们从前面描述日志缓冲区的内存结构时,知道重做记录中最重要的就下面列的这几列内 容。同时,下面的一行就表示一个改动向量):
 
行号 事务id file# block# row column value
1 T1 2 19 - - abc
2 T1 4 120 1 2 cdf
这时假设session 2发出其他更新语句:
update t set c1=10 where c1=9;
同样的道理,oracle找到该数据块(假设为[file#5,blk#200])放入buffer cache,并找到回滚段数据块(假设为[file#2,blk#30])存放旧值,生成重做记录,更新表的数据块,再次生成重做记录。这时的日志缓冲区 的结构类似如下:

行号 事务id file# block# row column value
1 T1 2 19 - - abc
2 T1 4 120 1 2 cdf
3 T20 2 30 - - 9
4 T20 5 200 20 1 10
这时,session 1又发出更新语句:update redo_test set name='xyz1' where id=2,并提交(commit)。
同样的方式处理回滚段和数据块,并生成重做记录。假设这时生成日志缓冲区假设为:

行号 事务id file# block# row column value
1 T1 2 19 - - abc
2 T1 4 120 1 2 cdf
3 T20 2 30 - - 9
 
4 T20 5 200 20 1 10
5 T1 2 19 - - abc
6 T1 4 120 2 2 xyz1
7 T1 commit SCN timestamp
这时,我们可以注意到,提交标记也被记录到了重做记录中。从我们前面转储出的结果中也可以看到“sta: 9”的内容,这就是提交标记。每次提交时,都会生成一个SCN号,SCN号越小,说明发生的越早,其所属的重做记录就越排在前面。一旦用户发出 commit语句,系统就会触发LGWR进程。这时,LGWR进程会将上面所显示的所有重做记录都写入联机日志文件中。注意,其中也包括尚未提交的事务 T20。
在LGWR写这些重做记录的过程中,又有其他session 发出更新语句,并提交。这时的日志缓冲区假设如下所示:

行号 事务id file# block# row column value
1 T1 2 19 - - abc
2 T1 4 120 1 2 cdf
3 T20 2 30 - - 9
4 T20 5 200 20 1 10
 5 T1 2 19 - - abc
6 T1 4 120 2 2 xyz1
7 T1 commit SCN timestamp 以上的重做日志正在由LGWR写入
------------------------------------------------------------------------------------------
8 T20 2 39 - - 289 在LGWR写时生成以下的重做日志
9 T20 5 498 220 3 190
 
10 T9 2 90 - - hhh
11 T9 9 100 20 9 xxx
12 T9 commit SCN timestamp
 
13 T18 2 189 - - 18
14 T18 10 29 300 10 20
15 T18 commit SCN timestamp
当LGWR写完第一批重做记录(第1到第7行)以后,就会立即开始写第二批重做记录(第8行到第15行)。注意,第二批重做记录中,存在两个 commit,但LGWR不会分成两次来写,而是一次就将它们全部写入。当LGWR在写完第1到第7行的改动向量以后,这部分的日志缓冲区内存就被释放 了,可以被新生成的重做记录所覆盖。
如果当前联机日志文件写完时,这时就需要转换到另外一个可写的联机日志文件上去,这个过程叫做日志切换。日志切换的大致过程包括:
1) 从控制文件中得到下一个可用的联机日志文件。
2) 记录写入当前联机日志文件的最后一个日志块的SCN(叫做high SCN)。关闭当前联机日志文件。
3) 增加SCN,再次操作控制文件,将下一个联机日志文件标志为CURRENT,判断前一个联机日志文件里包含的重做记录所对应的脏数据块是否都已经写入数据 文件,如果没有则标记为ACTIVE;如果是则标记为INACTIVE。如果数据库是归档模式,那么LGWR将前一个联机日志文件加入归档列表中,等待归 档。
4) 打开新的联机日志文件组中的所有成员,记录当前日志序列号(log sequence)和第一个日志块的SCN(叫做low SCN),新一轮的重做记录开始。
我们经常看到当前日志文件的状态为CURRENT,而前一个日志文件的状态为ACTIVE的情况。实际上,这是由于内存中存在很多脏数据块,而脏数据块的 写入是通过DBWR进程完成的。如果脏数据块没有积累到一定的量,DBWR是不会将它们写入数据文件的。所以,ACTIVE状态的日志文件表示该日志文件 里包含的重做记录所对应的脏数据块还没有被DBWR进程写入数据文件。事实上,日志切换时触发增量检查点(incremental checkpoint),CKPT将会触发DBWR写脏数据块。增量检查点只是在控制文件中记录这时在检查点队列上的脏数据块在第一次修改时所对应的日志 块在日志文件中的地址,这个地址叫做检查点位置(checkpoint position)。但是DBWR启动并不表示立即写脏数据块,除非脏数据块的数量达到一定程度,或超过一定时间等。我们来模拟一下这种情况。

SQL> select group#,status from v$log;
GROUP# STATUS
---------- ----------------
1 CURRENT
2 INACTIVE
3 INACTIVE
SQL
> create table t2 as select * from dba_objects;
SQL
> select group#,status from v$log;
GROUP# STATUS
---------- ----------------
1 ACTIVE
2 CURRENT
 
3 INACTIVE

我们可以看到,当创建了表t2的时候,发生了日志切换。如果没有看到日志切换,可以再删除表t2然后再创建表t2,如此反复几次,就能够引起日志切换。这 时我们看到2号日志文件为当前打开的日志文件,其状态为CURRENT。而1号日志文件为上次打开的日志文件,状态为ACTIVE,就说明其对应的脏数据 块还没有写入数据文件。这时我们可以等待一段时间,等待增量检查点的完成,也可以手工触发完全检查点(complete checkpoint),触发完全检查点时,DBWR将把所有脏数据块写入磁盘上的数据文件里。

SQL> alter system checkpoint;
SQL
> select group#,status from v$log;
GROUP# STATUS
---------- ----------------
1 INACTIVE
2 CURRENT
 
3 INACTIVE


可以看到,1号日志文件的状态从ACTIVE变成了INACTIVE,说明其对应的脏数据块都已经写入了联机日志文件中。
这 里要说明一点。增量检查点触发的DBWR写和完全检查点触发的DBWR写的优先级是不一样的,这也就是为何在上面的例子中进行日志切换以后,前一个日志的 状态为ACTIVE,而且要等一段时间以后其状态才能变为INACTIVE,而我们发出alte system checkpoint以后立即变为INACTIVE的原因。因为日志切换触发增量检查点,而增量检查点通知DBWR启动,但是由于这时触发DBWR启动的 条件的优先级较低,所以DBWR不会立即去写脏数据块,而是要等一段时间才会实际的写脏数据块。所以我们等待日志状态变为INACTIVE的时间就是等 DBWR开始真正写的时间加上DBWR实际写入数据文件所花费的时间。而alte system checkpoint触发完全检查点,其优先级很高,所以通过它触发的DBWR会立即去写脏数据块,所以我们等待日志状态变为INACTIVE的时间就是 DBWR实际写入数据文件所花费的时间。

我们可以设定初始化参数:log_checkpoints_to_alert为true,从而将检查点启动和结束的时间记录到跟踪文件里去。这里是所记录的信息的一个例子:

Wed Dec 13 18:27:48 2006
 Beginning
log switch checkpoint up to RBA [0x85.2.10], SCN: 2164686
Thread
1 advanced to log sequence 133
Current log# 3 seq# 133 mem# 0: /oracle/oradata/ora10g/redo03.log
Wed
Dec 13 18:32:45 2006
Completed
checkpoint up to RBA [0x85.2.10], SCN: 2164686
 ……
Wed
Dec 13 19:02:15 2006
Beginning global
checkpoint up to RBA [0x85.883.10], SCN: 2165818
Completed
checkpoint up to RBA [0x85.883.10], SCN: 2165818
阅读(680) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~