ORACLE的完全检查点和增量检查点
1、完全检查点
在Oracle8i之前,数据库的发生的检查点都是完全检查点。完全检查点会将数据缓冲区里面所有的脏数据块写入相应的数据文件中,同时将最新的checkpoint scn更新到所有的数据文件头部及控制文件。保证数据库的处于一致的状态。需要注意的是,完 全检查点产生的时候,CKPT并不是把当前完全检查点发生那一时刻的SCN更新到控制文件和数据文件头,而是将这个触发检查点时刻DBWn当前刚写完 dirty buffer对应的SCN更新到控制文件和数据文件头,也就是说,更新控制文件和数据文件头的SCN是滞后于完全检查点的发生那一时刻的SCN的,这个从恢复的原理也很容易理解,因为检查点发生的时候要写入dirty buffer还没有写入,自然不能立即更新成当前的SCN了。需 要注意的是, 在oracle8之前,由于没有chekpoint queue,也没有增量检查点的概念,发生完全检查点时,DBWn会以一种无序的方式将所有的 dirty buffer写出到数据文件,这个时候Oracle会冻结所有DML操作等候所有dirty buffer被写出,巨大的IO往往会影响到数据库的性 能。后来随着Oracle数据库的发展和buffer cache的不断增大,oracle 意识到这个单一的Full checkpoint机制已经不能满足需要,所以在Oracle 8i后提出增量检查点的概念,建立了checkpoint queue ,让dirty buffer header根据首次变化时候的顺序(LRBA)排列在queue里面。 这样DBWn只要顺着queue的顺序写,而其他进程不必等候dbwr的写完成就可以继续。 因此增量检查点的概念就由此产生了。
完全检查点在8i之后只有在下列两种情况下才会发生:
DBA手工执行alter system checkpoint的命令;
数据库正常shutdown (immediate,transcational,normal)。
2、增量检查点
CKPT每3秒一次的检查DBWn写进度并在控制文件中记录检查点位置(checkpoint position)和更新heartbeat信息
不 论数据块(buffer)更改几次,它在checkpoint queue里面的位置始终保持不变,checkpoint queue也只会记录它最早的RBA(这个最早的RBA其实就是Low RBA,也就是数据块第一次被修改时所对应的RBA),从而保证最早更改的数据块能够尽快从内存写入数据文件。DBWR每到一定的时机,就会被触发 (DBWn并不是只有当检查点发生的时候才写,它大约有10几种条件触发写操作),沿着检查点队列的顺序刷新脏块,同时CKPT进程,会监控着检查点队列 的长度,当检查点队列的长度达到一定限制时(具体有几个参数来确定checkpoing queue的长度,下面会提到比如log_checkpoint_timeout,fast_start_mttr_target等),CKPT会通知 DBWR写脏块。CKPT会根据几个参数的设置和I/O的速度以及繁忙程度,计算出来一个Target rba(目标rba),DBWn会沿着检查点队列,按照dirty buffer的Low RBA顺序将所有Target rba之前对应的脏块从内存写入数据磁盘文件。当CKPT通知完DBWn Target rba后,CKPT的任务就结束了。他并不会等待DBWn写完所有的Target rba之前的脏块。因此这里CKPT只是起到了一个通知DBWn进程写入的作用。
当完全检查点发 生的时候,Oracle一方面通知DBWn进行下一批写操作,另一方面是将这个触发检查点时刻DBWn当前刚写完dirty buffer对应的SCN写入数据文件头和控制文件,这个SCN就是checkpoint scn。但Oracle考虑到检查点SCN的间隔还是太大了,因为检查点的触发条件有限,周期可能比较长,有些情况下比如检查点需要5分钟左右才触发,那 这个时候系统crash再重新启动就意味着很可能系统需要5分钟左右才能启动。于是Oracle采用了一个heartbeat的概念,以3秒的频率将 DBWn写的进度反应到控制文件中,这样系统crash重新启动的时候将从更近的一个时间点开始恢复。Oracle这么做的目的就是要缩短崩溃恢复时间! 因此CKPT另外一个任务就是每3秒,检测一次DBWn的写进度。DBWn 是沿着检查点队列写脏块,由于这里有一个顺序的关系,所以DBWn的写的进度就是可衡量的,写到哪个buffer的时候该buffer的首次变化时候的 scn(对应了LRba)就是当前所有数据文件block的上面最新scn,但是由于无法适时的将DBWn的进度记录下来,所以Oracle选择了一些策 略。 其中就包括CKPT进程的检查点位置更新和心跳,所以说CKPT每3秒钟查看一下DBWn沿检查点队列写到了哪里,并且将这个位置设置为检查点位置 (checkpont position)。也就是说检查点位置之前的块,都是已被DBWn刷新到磁盘上的块。因此我们可以理解为,CKPT进程每3秒会根据DBWn写的进度设置并记录一个检查点位置,也就是说这个检查点位置就是由DBWn的在往Target RBA写过程中的进度决定的(如果没有dirty buffer产生,那么就不会更新检查点位置信息)。因 此CKPT每3秒会将检查点位置对应的数据块的rba (low cache rba-表示Instance Recovery时开始恢复的日志条目)更新和记录到控制文件的CHECKPOINT PROGRESS RECORDS区域,当然同时被记录进控制文件的还有heartbeat等其他信息。DBWn将检查点队列里面的dirty buffer写入到数据文件后,检查点的位置也要相应地往后移。
检 查点位置(checkpoint position)实际上就可以直接理解为是一个rba,他指向着重做日志文件中的某条重做记录。在此检查点位置前的重做记录,其对应的buffer cache中的dirty buffer已经被写进了数据文件,在此位置后的重做记录,所对应数据脏块有可能还在内存中。如果发生了实例崩溃,只需要在日志文件中找到检查点位置 (low cache rba),从此处开始应用所有的重做日志文件,就完成了前滚操作。实例崩溃后,再次启动数据库,oracle会到控制文件中读取low cache rba,这就是检查点位置。从此处开始应用重做日志,应用到on disk rba的位置。on disk rba是磁盘中重做日志文件的最后一条重做记录的rba。如 果某条重做记录的rba高于on disk rba,那说明此重做记录还没有被写进日志文件中,崩溃发生时,他是不可能被恢复的。on disk rba是oracle前滚操作的终点。比这个更高的rba,都应该还驻留在log buffer中。还没有被LGWR写入日志文件。所以是不能被用于恢复的。
在 DBWn写dirty buffer这个检查点过程中,Oracle也可以继续产生dirty buffer,DBWn也不是一次要把所有dirty buffer全部写到磁盘(不同于完全检查点的地方),这样就提高了检查点的效率,使得数据库要做恢复的时候从这个最新位置开始做恢复,而不是从数据文件 中的checkpoint scn(上一个完全检查点位置) 开始做恢复,这样将缩短恢复时间。
------------------
CKPT进程使用非常轻量级的控制文件更新协议,将当前的最低RBA(low cache rba)写入控制文件,为了减少频繁增量检查点的性能影响,CKPT在进行轻量级更新时,并不会改写控制文件中数据文件的检查点信息以及数据文件头信息,而只是记录控制文件检查点SCN(controlfile checkpoint scn)并且根据增量检查点增进RBA信息,不需要更改数据文件头信息。
转储控制文件: alter session set events 'immediate trace name controlf level 8';
DATABASE ENTRY
***************************************************************************
(size = 316, compat size = 316, section max = 1, section in-use = 1,
last-recid= 0, old-recno = 0, last-recno = 0)
(extent = 1, blkno = 1, numrecs = 1)
07/18/2014 01:02:22
DB Name "ORCL"
Database flags = 0x00404000 0x00001000
Controlfile Creation Timestamp 07/18/2014 01:02:30
Incmplt recovery scn: 0x0000.00000000
Resetlogs scn: 0x0000.000e2006 Resetlogs Timestamp 07/18/2014 01:02:35
Prior resetlogs scn: 0x0000.00000001 Prior resetlogs Timestamp 08/24/2013 11:37:30
Redo Version: compatible=0xb200400
#Data files = 5, #Online files = 5
Database checkpoint: Thread=1 scn: 0x0000.001637e6 ---增量检查不会更新此信息
Threads: #Enabled=2, #Open=1, Head=1, Tail=1
……
Max log members = 3, Max data members = 1
Arch list: Head=3, Tail=3, Force scn: 0x0000.00153c61scn: 0x0000.00000000
Activation ID: 1380958875
SCN compatibility 1
Auto-rollover enabled
Controlfile Checkpointed at scn: 0x0000.00166516 07/26/2014 02:38:53 -- 增量检查点只更新这个scn ,会比Dtabase checkpoint scn大
thread:0 rba:(0x0.0.0)
DATA FILE RECORDS
***************************************************************************
(size = 520, compat size = 520, section max = 1024, section in-use = 5,
last-recid= 38, old-recno = 0, last-recno = 0)
(extent = 1, blkno = 23, numrecs = 1024)
DATA FILE #1:
name #8: +DATA/orcl/datafile/system.256.853203575
creation size=0 block size=8192 status=0xe head=8 tail=8 dup=1
tablespace 0, index=1 krfil=1 prev_file=0
unrecoverable scn: 0x0000.00000000 01/01/1988 00:00:00
Checkpoint cnt:126 scn: 0x0000.001637e6 07/25/2014 23:45:24 ---增量检查不会更新此信息 ;数据文件开始scn
Stop scn: 0xffff.ffffffff 07/25/2014 17:49:56 ---数据文件结束scn
Creation Checkpointed at scn: 0x0000.00000007 08/24/2013 11:37:33
thread:0 rba:(0x0.0.0)
alter system switch logfile;切换日志会同步控制文件和数据文件头部的scn信息,但是不是每次切换都会同步,在我的试验中,有三组logfile
第一次不会同步控制文件和数据文件头部scn信息,第二次switch logfile比较久,是在同步。推理就是数据库会根据logfile的状态active,current根据情况同步信息。
SQL> select checkpoint_change#,file# from v$datafile;
CHECKPOINT_CHANGE# FILE#
------------------ ----------
1468242 1
1468242 2
1468242 3
1468242 4
1468242 5
SQL> select checkpoint_change#,controlfile_change# from v$database;
CHECKPOINT_CHANGE# CONTROLFILE_CHANGE#
------------------ -------------------
1468242 1472864
SQL> alter system switch logfile;
System altered.
SQL> select checkpoint_change#,file# from v$datafile;
CHECKPOINT_CHANGE# FILE#
------------------ ----------
1468242 1
1468242 2
1468242 3
1468242 4
1468242 5
SQL> select checkpoint_change#,controlfile_change# from v$database;
CHECKPOINT_CHANGE# CONTROLFILE_CHANGE#
------------------ -------------------
1468242 1472965
SQL> alter system switch logfile; -------------------------------------第二次switch logfile时间比较长,就是在写数据文件和控制文件
System altered.
SQL> select checkpoint_change#,file# from v$datafile;
CHECKPOINT_CHANGE# FILE#
------------------ ----------
1472965 1
1472965 2
1472965 3
1472965 4
1472965 5
SQL> select checkpoint_change#,controlfile_change# from v$database;
CHECKPOINT_CHANGE# CONTROLFILE_CHANGE#
------------------ -------------------
1472965 1472991
SQL>