ORACLE数据库技术实用详解
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

6.2 联机日志文件

从前面我们已经知道,联机日志文件在数据库里就像磁带一样,将数据库里所有数据块的变化都记录下来,记录下来的变化叫做重做记录(redo record)。注意,这里强调的是数据块的变化,而不是数据的变化。修改数据块的头部的标记信息时,也会产生重做记录。重做条目先在log buffer里产生,当出现某种事件(比如用户提交),则唤醒LGWR进程,将重做条目刷新到联机日志文件里。LGWR写联机日志文件时,就与写入磁带一样,都是向前的顺序写,而不像写数据文件那样,会前后地、随机地写。因此,LGWR写入联机日志文件的速度相对会很快。

在前面介绍Oracle数据库内存组织的时候,我们已经知道,联机日志文件存在的主要目的就是为了进行恢复。因为联机日志文件里记录了数据块的所有的变化,因此,我们可以用它来将数据库恢复到历史上的任何一个时间点。

6.2.1 日志切换

只要数据库处于运行状态,就会不断修改数据块,从而产生重做记录,并刷新到联机日志文件里。因此,重做记录可以是无限多的,而联机日志文件既不可能无限大,又不可能无限多。对Oracle来说,必须至少存在两个日志文件,并存在所谓日志切换的概念。

如果当前联机日志文件写完时,就需要转换到另外一个可写的联机日志文件上去,这个过程叫做日志切换。所有的日志文件使用都是一个循环的过程,通过日志切换实现。假设有三个日志文件:A、B和C。则写完A日志文件以后,从A切换到B;B写完以后,从B切换到C;C写完以后,从C又切换回到A。如此循环往复。

日志切换的过程大致包括以下几个步骤:

①从控制文件中得到下一个可用的联机日志文件。

②记录写入当前联机日志文件的最后一个日志块的SCN(叫做high SCN),关闭当前联机日志文件。

③增加SCN,再次修改控制文件,将下一个联机日志文件标记为CURRENT,判断前一个联机日志文件里包含的重做记录所对应的脏数据块是否都已经写入数据文件,如果没有则标记为ACTIVE;如果是,则标记为INACTIVE。如果数据库是归档模式,那么LGWR将前一个联机日志文件加入归档列表中,并唤醒ARCn进程进行归档。

④打开新的联机日志文件组中的所有成员,记录当前日志序列号(log sequence)和第一个日志块的SCN(叫做low SCN),新一轮的重做记录开始。

我们经常看到当前日志文件的状态为CURRENT,而前一个日志文件的状态为ACTIVE的情况。实际上,这是由于内存中存在很多脏数据块,而脏数据块的写入是通过DBWn进程完成的。如果脏数据块没有积累到一定的量,DBWn是不会将它们写入数据文件的。所以,ACTIVE状态的日志文件表示该日志文件里包含的重做记录所对应的脏数据块还没有被DBWn进程写入数据文件。事实上,日志切换时触发增量检查点(incremental checkpoint),CKPT将会触发DBWn写脏数据块。增量检查点只是在控制文件中记录这时在检查点队列上的脏数据块在第一次修改时所对应的日志块在日志文件中的地址,这个地址叫做检查点位置(checkpoint position)。但是DBWn启动并不表示立即写脏数据块,除非脏数据块的数量达到一定程度或超过一定时间等。有关DBWn和CKPT的详细信息请参考第5.4节。

我们来模拟一下这种情况。

    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,就说明其对应的脏数据块还没有写入数据文件。这时我们可以等待一段时间,等待增量检查点的完成,也可以手工触发完全检查点。触发完全检查点时,DBWn将把所有脏数据块写入磁盘的数据文件里。

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

可以看到,1号日志文件的状态从ACTIVE变成了INACTIVE,说明其对应的脏数据块都已经写入了联机日志文件中。

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

我们可以设定初始化参数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

从上面可以看到,由于日志切换而发生的增量检查点从18:27:48开始,到18:32:45结束,用了5分钟的时间。而我们强制进行完全检查点,则只用了大概1秒钟不到的时间。实际上,DBWR在实际写入数据文件所花费的时间都是一样的,也就是不到1秒。5分钟的差别就在于DBWR等了5分钟才实际开始写数据文件。

由于联机日志文件的重要性,因此Oracle强烈建议以组的形式建立日志文件。数据库中至少两个日志文件组(log group),同时一个日志文件组至少包含两个日志文件,每个日志文件叫做日志成员(log member)。

LGWR在写重做记录的时候,以组为单位,并行地写入组里所有日志成员。同一个日志文件组里的所有日志成员的内容都相同,同一个组里的所有日志文件成员大小都必须相同。而且Oracle建议每个日志文件成员位于不同的硬盘上。

日志切换也是以组为单位,假设三组日志文件组:A组、B组和C组。则写完A组的日志,从A组切换到B组;B组写完切换到C组;C组写完又切换回A组。这样的话,如果一个日志文件损坏,只要该日志文件所在的组的其他成员仍然可用,则整个日志文件组就仍然能够对外工作。数据库是不会宕机的,只是会在告警日志文件里记录该情况。

我们也可以手工强制进行日志切换。使用命令:

    alter system switch logfile;

6.2.2 管理日志文件

管理日志文件包括创建日志文件组、向日志文件组里添加新的日志文件成员、删除日志文件成员等。这些工作都可以通过Database Control完成,如图6-10所示。

图6-10 创建联机日志文件组

单击Administration→Redo Log Groups,进入图6-10中②部分所示的界面。单击图②部分的Create按钮,进入图③部分,在这里我们可以输入日志文件组的组号、日志文件组大小(大小尺寸是在日志文件组上定义的,而不是单个的日志文件成员),单击Add按钮还可以进入④部分所示的界面。在这里我们可以输入日志文件成员以及所在的路径。在④部分可以看到名为Reuse File的复选框,选中该复选框说明所输入的文件已经存在,不需要重建,只要重用即可。

对于联机日志文件的管理,我们还可以在图6-10中的②部分选择Actions列表,如图6-11所示。在这里选中要进行的管理选项,然后单击Go按钮即可。

图6-11 管理联机日志文件组

对Actions列表中的选项说明如下。

Clear logfile:清除指定的联机日志文件组所有的成员。在日志文件组里丢失或损坏部分成员时,可以清除该日志文件组,Oracle会自动创建丢失或损坏的成员。被清除的日志文件组的状态必须是inactive的,如果为active或者current,则说明其中包含的重做记录所对应的脏块仍然在内存里,这些重做还不能被清除。对应的SQL语法如下所示。

    alter database clear logfile group 3;

Create Like:根据指定的联机日志文件组新建立一个类似的组。

Force checkpoint:强制启动检查点进程。

Generate DDL:生成日志文件组的DDL命令。

Sizing advice:这是Oracle 10g所引入的顾问,用来帮助我们确定最佳的日志文件组尺寸。只有在我们设置了初始化参数fast_start_mttr_target以后,才能使用该顾问。实际上,查询v$instance_recovery视图的optimal_logfile_size列,该列的值就显示了顾问所得出的联机日志文件的最佳尺寸。

Switch logfile:强制进行日志切换。