前言:你知道对数据库修改的操作会通过记录到redo log中;知道数据库断电down掉或shutdown abort后,重新启动数据库时需要利用redo log对提交但没有被刷入磁盘中的数据进行实例恢复。好像我们明白了这个知识点,但如果你继续深入细致地思考一下,你的脑子里一定会有很多疑问。如何确定实例恢复时需要应用哪些日志,实例的恢复过程会有多久,如果保证在恢复时的一致性问题。
一、什么是检查点:
简单地讲,检查点(checkpoint)是一个事件,不定期地在满足一定条件后,由CKPT进程发出,由DBWn进程将Data buffer cache中的已修改的数据写入到磁盘中。内存中的数据越少,我们需要进行实例恢复时所需要的时间也就越短。缩短实例恢复的时间同时记录恢复时重做日志的开始位置是检查点存在的一个主要目的,这是提到检查点时,你首先应该想到的,然后再去思考它为什么能缩短恢复时间(下面的工作原理将会讲述)。而不是只知道它用来向磁盘刷新数据,数据被刷新到磁盘不一定需要检查点,还有很多触发条件会使内存中的数据不经检查点而直接刷新到磁盘。
二、检查点分类:
完全检查点(normal checkpoint)
增量检查点(increment checkpoint)
三、检查点的工作原理
1. 在说明检查点的工作原理之前,首先需要理解一些即将会涉及到的术语。
RBA(redo byte address),即重做日志块的地址,通过这个地址来定位恢复时需要利用的重做日志块,RBA是一串地址数字,由三部分组成:
l 日志文件序列号
l 日志文件块编号
l 重做日志记录在日志块中的起始偏移字节数
通常使用的RBA有三种形式:
LRBA: 数据缓存(buffer cache)中一个脏块第一次被更新的时候产生的重做日志记录在重做日志文件中所对应的位置就称为LRBA。
HRBA: 数据缓存(buffer cache)中一个脏块最近一次被更新的时候产生的重做日志记录在重做日志文件中所对应的位置就称为HRBA。
checkpoint RBA:当一个checkpoint事件发生的时候,checkpoint进程会记录下当时所写的重做日志块的地址即RBA,此时记录的RBA被称为checkpoint RBA。从上一个checkpoint RBA到当前的checkpoint RBA之间的日志所保护的buffer cache中的脏块接下来将会被写入到数据文件当中去
比如说,用户发出了一条Update命令来更新了缓存中的块A,块A现在变成了脏块,同时oracle会为A上的update操作生成一条重做记录,这条重做记录在redo log中的位置就是RBA.然后块A就等待着被刷新到磁盘中,此时块A还没有被刷到磁盘,但用户又发出了一条更新A块的命令,这又会生成一条重做记录,对应一个RBA。则第一条update命令对应的重做记录的RBA称为块A的lrba(low rba),第二条更新命令对应的rba,被称为hrba(high rba).
Checkpoint queue:Oracle将缓存中被修改的脏块按照lrba的顺序组成一个队列,这条队列记录了缓存中块第一次被修改的先后顺序。在检查点时,DBWn进程按照这条队列将脏块写入到磁盘上的数据文件中,这样也保证了最先修改的块先被写入到磁盘中。队列的引入是为了支持增量检查点的。
2. 完全检查点的工作过程:
一个完全checkpoint可以分三个阶段:
l 第一阶段,checkpoint进程开始一个checkpoint事件,并记录下checkpoint RBA,这个通常是当前的RBA。
l 第二阶段,checkpoint进程通知DBWn进程将所有checkpoint RBA之前的buffer cache里面的脏块写入磁盘。
l 确定脏块都被写入磁盘以后进入到第三阶段,checkpoint进程将checkpoint信息(SCN)写入/更新数据文件和控制文件中。SCN为发出检查点命令时对应的SCN。
3. 完全检查点的触发条件:
l 发出checkpoint命令,通过alter system checkpoint
l Shutdown abort外的关库命令
l 运行alter tablespace read only时
l 对数据文件进行热备时,针对该数据文件的checkpoint也会进行,通过alter tablespace tbs begin backup
8i以前,alter system switch log会触发完全检查点,但现在是增量检查点。
4. 增量检查点:
特别注意,增量检查点和完全检查点是存在不同之处的,上面的两点讨论的是完全检查点,下面将讲述增量检查点的工作过程。
因为每次的完全检查点都会将buffer cache中的脏块完全刷新到磁盘,这样会产生一个很大的I/O消耗,频繁的完全检查点操作对系统性能有很大的影响,为此oracle引入增量检查点的概念。前面我们提到检查点队列的概念。有了检查点队列之后,脏块按照首次变脏的时间顺序排列,DBWR每到一定的时机,就会被触发,沿着检查点队列的顺序刷新脏块,具体在oracle中有几个参数用来确定检查点队列的长度.另有一个CKPT进程,会监控着检查点队列的长度,当检查点队列的长度达到一定限制时,CKPT会通知DBWR写脏块.CKPT会根据参数的设置和I/O的速度以及繁忙程度,计算出来一个Target rba(目标rba),DBWR会沿着检查点队列,将所有Target rba之前的脏块刷新到磁盘.当CKPT通知完DBWR Target rba后,CKPT的任务就结束了.他并不会等待DBWR写完所有的Target rba之前的脏块.通知DBWR写脏块,这是CKPT的任务之一,CKPT另有一个任务,就是每3秒,检测一次DBWR的写进度.检查点队列最前面的块被称为检查点位置.DBWR是沿着检查点队列写脏块的,CKPT每3秒钟查看一下DBWR沿检查点队列写到了哪里,并且将这个位置设置为检查点位置.也就是说检查点位置之前的块,都是已被DBWR刷新到磁盘上的块.这个3秒一次检查DBWR进度的工作,也是CKPT的一个重要的任务.CKPT每3秒一次将检查点位置记录进控制文件,当然同时被记录进控制文件的还有'心跳'等其他信息.CKPT每3秒一次的工作和CKPT定期触发DBWR,这两项操作合一起被称为--增量检查点.
下面是CKPT每3秒写入控制文件的内容:
SYS@PROD> alter session set events 'immediate trace name controlf level 8';
Session altered.
这条语句的作用将控制文件的内容转储(dump)到user_dump_dest参数指定的目录下找到最新改动过的跟踪文件,从中找出一条ckpt写入控制文件的记录。
****************************************************CHECKPOINT PROGRESS RECORDS
****************************************************
(size = 8180, compat size = 8180, section max = 4, section in-use = 0,
last-recid= 0, old-recno = 0, last-recno = 0)
(extent = 1, blkno = 2, numrecs = 4)
THREAD #1 - status:0x2 flags:0x0 dirty:0
low cache rba:(0xffffffff.ffffffff.ffff)[注释:此为检查点开始的位置] on disk rba:(0x9.12a9.0)[日志文件中最后一条日志的的位置]
on disk scn: 0x0000.00070b30 03/27/2013 21:46:44
resetlogs scn: 0x0000.0006c02f 03/20/2013 15:17:18
heartbeat: 810592759 mount id: 222393069
Flashback log tail log# 4 thread# 1 seq 30 block 436 byte 0
这里所谓的ckpt的每3秒写,并不是必须的,必须在增量检查点期间的每3秒写,而不是总是不停的每3秒写一次。
检查点位置是是个rba,他指向着重做日志文件中的某个重做记录.在此位置前的重做记录,其对应的信息已经被写进了数据文件,在此位置后的重做记录,所对应的是数据块,有可能还在内存中.如果发生了实例崩溃,只需要在日志文件中找到检查点位 置,从此处开始应用所有的重做日志文件,就完成了前滚操作.实例崩溃后,再次启动数据库,oracle会到控制文件中读取low cache rba,这就是检查点位置.从此处开始应用重做信息,应用到on disk rba处.on disk rba是磁盘中重做日志文件的最后一 条重做记录的rba. 如果某条命令的重做记录的rba高于on disk rba,那说明此重做记录还没有被写进日志文件中,崩溃发生时,他是不可能被恢复的.on disk rba是oracle前滚操作的终点.on disk 顾名思义 就是'在磁盘上'的意思.比这个更高 的rba,都在log buffer中,还没有来的急被写进磁盘中的日志文件.所以是不能被用于恢复的。
5. 与增量检查点有关的几个参数
log_checkpoint_interval
设定两次checkpoint之间重做日志块(重做日志块和系统数据块是一样的)数,当重做日志块数量达到设定值的时候将触发checkpoint。
log_checkpoint_timeout
设定两次checkpoint之间的间隔时间,当超时值达到时增量checkpoint将被触发。Oracle建议不用这个参数来控制,因为事务(transaction)大小不是按时间等量分布的。将此值设置成0时将禁用此项设置。
fast_start_io_target
因为log_checkpoint_interval主要看的时候重做日志块的数量,并不能反应buffer cache中脏数据块的修改,因此Oracle又引入了这个参数来实现当脏数据块达到一定数量的时候触发checkpoint,不过此参数实际上控制的是恢复时所需IO的数量。
fast_start_mttr_target
l 此参数是在9i中引入用来代替前面的三个参数的,它定义了数据块崩溃后所需要的实例恢复的时间,Oracle在实际上内在的解释成两个参数:fast_start_io_target和log_checkpoint_interval.如果这两个参数没有显式的指定,计算值将生效.。
l fast_start_mttr_target可以设定的最大值是3600,即一个小时。它的最小值没有设限,但是并不是说可以设置一个任意小的值,这个值会受最小dirty buffer(最小为1000)的限制,同时还会受初始化时间以及文件打开时间的限制。
l 在设置此参数的时候要综合考虑系统的IO,容量以及CPU等信息,要在系统性能和故障恢复时间之间做好平衡。
l 将此参数设置成0时将禁用 fast-start checkpointing,这样能见效系统负载但同时会增加系统的恢复时间。
l 如果fast_start_io_target or log_checkpoint_interval被指定,他们会自动覆盖由fast_start_mttr_target参数计算出来的值。
在10g中,数据库能根据各种系统参数的设置值来自动调整检查点的执行频率,以获得最好的恢复时间以及系统的正常运行影响最小。通过自动checkpoint调整,Orach能在系统低IO操作的时候将脏块写入到数据文件中,因此即时DBA没有设置checkpoint 相关的参数值或是设置了一个不合理的值的时候系统还是能获得一个很合理的系统恢复时间。
10g中的增量checkpoint更能体现它持续活动的特点,在10g中,增量checkpoint不是在某一个特定的条件下触发,而是由数据库根据系统参数设置自动触发。
6. 增量检查点与完全检查点的不同
完全checkpoint会将checkpoint的信息写入到控制文件以及数据文件头中
增量checkpoint只会将RBA信息写入到控制文件中。
四、查看一下系统的CHECKPOINT动作
1.完全检查点的查看:
通过设置参数log_checkpoints_to_alert为ture,使checkpoint信息记录到alert文件中,实现checpoint操作的跟踪。
SYS@PROD>alter system set log_checkpoints_to_alert=true;
System altered.
在v$datafile_header里也记录了完全检查点事件的相关信息,包括检查点时间的时间,检查点事件对应的scn,发生的检查点次数。
手动执行一次完全检查点
SYS@PROD> alter system checkpoint;
System altered.
查看alert下最新产生的日志信息:
Beginning global checkpoint up to RBA [0xa.2b0f.10], SCN: 472402
Completed checkpoint up to RBA [0xa.2b0f.10], SCN: 472402
再来切换一次日志看看:
SYS@PROD> alter system switch logfile;
System altered.
日志信息:
Thu Mar 28 19:33:26 2013
Beginning log switch checkpoint up to RBA [0xc.2.10], SCN: 472510
Thread 1 advanced to log sequence 12
Current log# 1 seq# 12 mem# 0: /u01/app/oracle/oradata/PROD/redo01.log
Current log# 1 seq# 12 mem# 1: /u01/app/oracle/oradata/PROD/disk2/redo01_b.log
Thu Mar 28 19:42:09 2013
Completed checkpoint up to RBA [0xc.2.10], SCN: 472510
可以看到检查点是在过了一段时间(这里是9分钟)之后才完成的,日志切换时的检查点是一个级别较低的完全检查点,为了性能上的考虑,延后了完全检查点的完成时间。数据库先记录下发出命令时刻的scn,ckpt进程不会推动DBWn去写脏数据,而是让DBWn按照自己的状态去写脏数据,等到写到发出命令时刻的scn时,ckpt进程再去更新控制文件和数据文件头。但我们可以看到此检查点对应的SCN与日志切换的SCN是相同的,对应着Thu Mar 28 19:33:26 2013
这个时间点的SCN。
SYS@PROD> select scn_to_timestamp(472510) from dual;
SCN_TO_TIMESTAMP(472510)
----------------------------------------
28-MAR-13 07.33.26.000000000 PM
顺便也来查看一下v$datafile_header中的记录
SYS@PROD> select file# no,tablespace_name,dbms_flashback.get_system_change_number current_scn,to_char(checkpoint_time,'yyyy-mm-dd hh24:mi:ss') ckpt_dt,checkpoint_change# ckpt_Scn,checkpoint_count from v$datafile_header;
NO TABLESPACE CURRENT_SCN CKPT_DT CKPT_SCN CHECKPOINT_COUNT
------ ------------- --------------------- -------------------------- ----------- ---------------
1 SYSTEM 473168 2013-03-28 19:33:26 472510 58
2 UNDOTBS 473168 2013-03-28 19:33:26 472510 57
3 SYSAUX 473168 2013-03-28 19:33:26 472510 57
4 EXAMPLE 473168 2013-03-28 19:33:26 472510 45
可以看到日志切换时的完全检查点的信息更新了数据文件头,其SCN与日志信息中的SCN一致,检查点时间为命令发出的时刻,而不是检查点完成的时间。
2.增量检查点的查看:
当前所知只有在LOG_checkpoint_TIMEOUT设置了非0值之后触发的增量 checkpoint会在alert文件中有记录,其他条件触发的增量checkpoint都不会记录在alert文件中。
为了尽快看到掩饰效果,这里将此参数设置为60S
SYS@PROD> alter system set log_checkpoint_timeout=60;
System altered.
Alert文件中的增量检查点记录:
Thu Mar 28 20:10:14 2013
Incremental checkpoint up to RBA [0xc.d41.0], current log tail at RBA [0xc.d41.0]
Thu Mar 28 20:11:14 2013Incremental checkpoint up to RBA [0xc.d41.0], current log tail at RBA [0xc.d41.0]
Thu Mar 28 20:12:14 2013
Incremental checkpoint up to RBA [0xc.d41.0], current log tail at RBA [0xc.d41.0]
Thu Mar 28 20:13:14 2013
Incremental checkpoint up to RBA [0xc.d41.0], current log tail at RBA [0xc.d41.0]
SYS@PROD> select CPDRT,CPLRBA_SEQ||'.'||CPLRBA_BNO||'.'||CPLRBA_BOF "low rba",CPODR_SEQ||'.'||CPODR_BNO||'.'||CPODR_BOF "On disk RBA",CPODS,CPODT,CPHBT from x$kcccp;
CPDRT low rba On disk RBA CPODS CPODT CPHBT
---------- --------------- ------------------- ---------------- ------------------------------ --------
00005 12.3788.0 12.3793.0 473922 03/28/2013 20:19:32 810601752
说明:
CPDRT列是检查点队列中的脏块数目.
CPODS列是on disk rba的scn
CPODT列是on disk rba的时间戳
CPHBT列是心跳
补充:
SCN,system change number,系统变更号,塔提供oracle数据库的内部时钟机制,定义数据库在某个确切的时间提交的版本,用于维护数据库的一致性。
在控制文件中为每一个数据文件保存着一个checkpoint scn和一个stop scn.checkpoint scn是一个完全检查点对应的snc,stop scn只有针对数据文件有stop scn这个概念,但是它在控制文件中存放着(具体作用后面讲述)。可以通过:
Selectname,checkpoint_change#,last_change#from v$datafile;
Select checkpoint_change# from v$database;
同时在数据文件头还存储着checkpoint scn,可以查看:
Select name,checkpoint_change# from v$datafile_header;
当一个完全检查点完成后,(注意,我这里说的是完全检查点,而不是增量检查点,增量检查点并不会做这样更新操作,下面会验证)oracle会更新控制文件中的checkpoint scn,以及数据文件头中的checkpoint scn。
当数据库正常shutdown(immediate,transcational,normal),执行完全检查点,更新存储在控制文件中的数据文件的stop scn,此值等于数据文件头中的checkpoint scn。
这样做的目的是什么呢?
1. 下次启动数据库时,oracle会进行两次检查;第一次看数据文件头中的checkpoint scn与存储在控制文件中的数据文件的checkpoint scn;如果相等,进行第2次检查,检查数据文件头中的checkpoint scn与存储在控制文件中的数据文件的stop scn,如果也相等,则不需要进行恢复操作;每个数据文件都做这样的检查,然后打开数据库,并将stop scn 重新置为无穷大。
2. 如果abort数据库,则不会执行完全检查点,存储在控制文件中的数据文件的stop scn仍为无穷大;下次启动数据库做两次检查时,如果第1次相等,再进行第2次比较时,数据文件头的checkpoint scn一定小于stop scn,则需要进行实例的恢复,进行相应的前滚和回滚
3. 如果用备份代替了数据文件在启动数据库,做第一次比较时,数据文件头的checkpoint scn一定小于控制文件中的数据库文件的checkpoint scn;或者用备份的控制文件代替了控制文件再启动数据库,这时数据文件头的checkpoint scn一定大于存储在控制文件中的数据文件的checkpoint scn;只要比较不相等,就需要进行介质恢复。
上面的括号里有一段这样的话:(注意,我这里说的是完全检查点,而不是增量检查点,增量检查点并不会做这样更新操作,下面会验证)
首先,下面是alert 日志文件中的最新信息:
Beginning log switch checkpoint up to RBA [0xc.2.10], SCN: 472510
Thread 1 advanced to log sequence 12
Current log# 1 seq# 12 mem# 0: /u01/app/oracle/oradata/PROD/redo01.log
Current log# 1 seq# 12 mem# 1: /u01/app/oracle/oradata/PROD/disk2/redo01_b.log
Thu Mar 28 19:40:19 2013
Incremental checkpoint up to RBA [0xc.2.0], current log tail at RBA [0xc.873.0]
Thu Mar 28 19:42:09 2013
Completed checkpoint up to RBA [0xc.2.10], SCN: 472510
Thu Mar 28 20:10:13 2013
ALTER SYSTEM SET log_checkpoint_timeout=60 SCOPE=BOTH;
Thu Mar 28 20:10:14 2013
Incremental checkpoint up to RBA [0xc.d41.0], current log tail at RBA [0xc.d41.0]
Thu Mar 28 20:11:14 2013
Incremental checkpoint up to RBA [0xc.d41.0], current log tail at RBA [0xc.d41.0]
Thu Mar 28 20:12:14 2013
Incremental checkpoint up to RBA [0xc.d41.0], current log tail at RBA [0xc.d41.0]
从日志中的信息看到,在一次SCN为472510的完全检查点之后又紧接着发生了3次增量检查点,但我们此时来查看一下数据文件头和控制文件中存储的checkpoint scn:
在控制文件中存储的checkpoint scn:
SYS@PROD> select checkpoint_change# from v$database;
CHECKPOINT_CHANGE#
------------------
472510
SYS@PROD> select name,checkpoint_change#,last_change# from v$datafile;
NAME CHECKPOINT_CHANGE# LAST_CHANGE#
-----------------------------------------
/u01/app/oracle/oradata/PROD/system01.dbf 472510
/u01/app/oracle/oradata/PROD/undotbs01.dbf 472510
/u01/app/oracle/oradata/PROD/sysaux01.dbf 472510
/u01/app/oracle/oradata/PROD/disk1/example.dbf 472510
/u01/app/oracle/oradata/PROD/disk1/indx.dbf 472510
/u01/app/oracle/oradata/PROD/disk1/tools.dbf 472510
/u01/app/oracle/oradata/PROD/disk1/oltp.dbf 472510
数据文件头中的checkpoint scn
SYS@PROD>select name,checkpoint_change# from v$datafile _header;
NAME CHECKPOINT_CHANGE#
------------------------------------------
/u01/app/oracle/oradata/PROD/system01.dbf 472510
/u01/app/oracle/oradata/PROD/undotbs01.dbf 472510
/u01/app/oracle/oradata/PROD/sysaux01.dbf 472510
/u01/app/oracle/oradata/PROD/disk1/example.dbf 472510
/u01/app/oracle/oradata/PROD/disk1/indx.dbf 472510
/u01/app/oracle/oradata/PROD/disk1/tools.dbf 472510
/u01/app/oracle/oradata/PROD/disk1/oltp.dbf 472510
可以看到数据文件的checkpoint scn与alert日志中记录的最后一次完全检查点对应的scn相同,并没有受到后续的增量检查点的影响。
ballontt
2013/3/28
----The End---