Oracle_检查点
|
|
详细论述增量检查点篇 **为什么要有检查点? 被修改过的块,在oracle中都被统称为脏块.所有的脏块被一个链表串起来,称做检查点队列.在buffer cache中,每一个块都有一个buffer header 简称BH,在BH中有一个ckptq项,此项目中记录了指向检查点队列上一个块和下一个块的指针.如果某一个块不在检查点队列中,他的ckptq项为空.通过ckptq项oracle将所有的脏块串成了一个双向链表.这个双向链表就是检查点队列了. 1,只有脏块才会在检查点队列中,非脏块的ckptq为空. 2,当块首次被更改时,块会立即被加进检查点队列.如果检查点队列中的脏块再次被修改,并不会改变其在检查点队列中的位置. 3,检查点队列中脏块的排列顺序:根据第2点,所有脏块按照首次被更改的时间的顺序排列.更准确点说:按照块的LRBA排列. **什么是RBA LRBA HRBA RBA就是重做块地址,比如说,用户发出了一条update命令,更新了块A,块A现在变成了脏块,oracle会为他生成一条重做记录.这条重做记录在重做日志文件中的位置就是rba(redo block address).过了一会儿,假如:块A依然还是脏块,此时.用户又发出一条更新块A的命令,这又会生成一条重做记录.第一条更新命令对应的重做记录的rba被称为块A的lrba(low rba),第二条更新命令对应的rba,被称为hrba(high rba).其实,按照lrba来排列,就是按照块首次被修改的顺序来排列. 下面说说DBWR写脏块的方式,有了检查点队列之后,脏块按照首次变脏的时间顺序排列,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秒,检测一次BWR的写进度.检查点队列最前面的块被称为检查点位置.DBWR是沿着检查点队列写脏块的,CKPT每3秒钟查看一下DBWR沿检查点队列写到了哪里,并且将这个位置设置为检查点位置.也就是说检查点位置之前的块,都是已被DBWR刷新到磁盘上的块.这个3秒一次检查DBWR进度的工作,也是CKPT的一个重要的任务.CKPT每3秒一次将检查点位置记录进控制文件,当然同时被记录进控制文件的还有'心跳'等其他信息.CKPT每3秒一次的工作和CKPT定期触发DBWR,这两项操作合一起被称为--增量检查点. 下面的就是CKPT每3秒写进控制文件的信息 SYS @ cuug > alter session set events 'immediate trace name controlf level 8'; Session altered. 会话已更改。 具体内容如下: *************************************************************************** CHECKPOINT PROGRESS RECORDS *************************************************************************** (size = 8180, compat size = 8180, section max = 11, section in-use = 0, last-recid= 0, old-recno = 0, last-recno = 0) (extent = 1, blkno = 2, numrecs = 11) THREAD #1 - status:0x2 flags:0x0 dirty:89 low cache rba
0x2ad.908.0)[检查点位置] on disk rba
0x2ad.d2f.0)[最后一条重做记录的rba] on disk scn: 0x0000.00237745 03/02/2008 15:03:44[最后一条重做记录的scn] resetlogs scn: 0x0000.0008297b 08/27/2007 09:51:58 heartbeat: 648318959[心跳] mount id: 1201288562 ... ... 这里面的大多数信息可以通过x$kcccp中看到. SQL> 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 ---------- --------------- --------------- ---------------- -------------------- ---------- 35 686.124.0 686.220.0 2325376 03/02/2008 15:18:54 648319278 说明: CPDRT列是检查点队列中的脏块数目. CPODS列是on disk rba的scn CPODT列是on disk rba的时间戳 CPHBT列是心跳 检查点位置是个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中,还没有来的急被写进磁盘中的日志文件.所以是不能被用于恢复的. 下面假设一个实例恢复的例子: Table表每行2000个字节,块大小8K,每块可容纳table的3行,按如下发布7条更新命令: Update table set name=low(name) where id=1; ------块1 RBA :692.2998.10 Update table set name=low(name) where id=2; ------块1 RBA :692.3015.10 Update table set name=low(name) where id=4; ------块2 RBA :692.3024.10 Update table set name=low(name) where id=7; ------块3 RBA :692.3033.10 Update table set name=low(name) where id=3; ------块1 RBA :692.3102.10 Update table set name=low(name) where id=10; ------块4 RBA :692.3127.10 Update table set name=low(name) where id=13; ------块5 RBA :692.3136.10
上面七条更新命令后,每块状态为:
Lrba就是块首次变脏时的RBA,而Hrba,是最后一次改变块中信息,所对应的重做记录的RBA。1号块外被修改两次,Lrba和Hrba不同。2到5号块只被修改一次,Lrba和Hrba相同。 相应的重做记录有:
假如此时,1号块和2号块已经变得不脏,3、4、5号块仍是脏块,所有的脏块依Lrba顺序按列为检查点队列,其中检查点队列头(此处是3号块)的Lrba就是检查点位置,此处为692.3033.10。这个值被记录在控制文件中。如果发生了实例崩溃,Oracle将从控制文件中取出692.3033.10,到692号重做日志中,找到第3033块,从此处开始,应用所有的重做日志,直到重做日志文件的最未尾。而重做日志文件的最未尾重做记录的RBA,又叫On disk rba。从检查点位置处,应用重做记录到On disk rba处,这个过程就是前滚。 如下几个参数可以用来限制检查点队列的长度: 1,fast_start_io_target 该参数用于表示数据库发生Instance Recovery 的时候需要产生的IO总数,他通过v$filestat的AVGIOTIM来估算的.比如我们一个数据库发生Instance Crash后需要在10分钟内恢复完毕,假定OS的IO每秒为500个,那么这个数据库发生Instance Recovery的时候大概产生500*10*60=30,000次IO,也就是我们将可以把fast_start_io_target设置为30000. 2,fast_start_mttr_target 我们从上面可以看到fast_start_io_target来估算检查点位置比较麻烦.oracle为了简化这个概念,从9I开始引入了fast_start_mttr_target这么一个参数,用于表示数据库发生Instance Recovery的时间.以秒为单位,这个参数我们从字面上也比较好理解,其中的mttr是mean time to recovery的简写,如上例中的情况我们可以将fast_start_mttr_target设置为600.当设置了fast_start_mttr_target后,fast_start_io_target这个参数将不再生效,从9I后fast_start_io_target这个参数被oracle废除了. 3,log_checkpoint_timeout 该参数用于表示检查点位置和重做日志尾之间的时间间隔,以秒为单位,默认情况下是1800秒,这个参数实际上表示了脏块保持脏状态的最长时间.如果它被定为1800秒,没有脏块保持1800秒后,还是为脏. 设log_checkpoint_timeout为1800秒 相比fast_start_mttr_target,它也是时间,但它的时间值表示完成恢复操作所需要的时间,即从最后的检查点位置开始,应用所有日志直到日志末尾所需要的时间.而本参数表示从最后的检查点位置开始,到日志末尾经过的时间. 在标准版中,本参数的最小值是900. 4,log_checkpoint_interval 该参数是表示检查点位置和重做日志末尾的块的数量.以OS表示. 5,90% OF SMALLEST REDO LOG Oracle内部事实上还将重做日志末尾前面90%的位置设为检查点位置,这不是一个参数,这是oracle内部规定的一个触发增量检查点的事件. 上面这些条件,严格来说,并不是控制检查点什么时候发生,而是控制检查点队列中可以有多少个块.在前4个参数中,9I中oracle推荐使用fast_start_mttr_target替代第一个 fast_start_io_target. fast_start_mttr_target,log_checkpoint_timeout,log_checkpoint_interval和90% OF SMALLEST REDO LOG 可以同时使用.考虑这样一种情况,如果上面的这些触发增量检查点的参数都被设置,并且在某一时刻,这几个参数一起被触发,但他们指定的Target RBA位置可能不尽相同,oracle将离日志末尾最近的那个位置认为检查点位置,如下图所示: 在这种情况下,将会把log_checkpoint_interval的位置定为下一增量检查点的Target RBA. 在9I后,对检查点频率,建议只设置fast_start_mttr_target.根据需要,也可以通过设置log_checkpoint_timeout,设置一个脏块保持脏状态的最大时间,而其他两个参数fast_start_io_target,log_checkpoint_interval建议不再使用. oracle写脏块并不一定都从检查点队列中写.在v$sysstat视图中,有两项关于物理写的资料.physical writes 和physical writes non checkpoint.也就是说,oracle将对脏块的写分为两类.一类是通过检查点的写,一类是不通过检查点的写.我把它叫做检查点无关写.比如说:当表空间脱机时,会把隶属于该表空间的所有脏块都写进数据文件,但是不会发生检查点,这个写就是检查点无关写. 还有其他的情况会发生检查点无关写,我会在以后的实验中介绍.一个小实验,证明下检查点无关写:为了避免检查点对实验的影响,将检查点的发生频率设置的低一些. 命令如下: alter system set fast_start_mttr_target=0; alter system set log_checkpoint_timeout=3600; 步骤一:在实验前先观察下当前物理写的值: SQL> select * from v$sysstat where name='physical writes non checkpoint'; STATISTIC# NAME CLASS VALUE STAT_ID ---------- ------------------------------ ---------- ---------- ---------- 67 physical writes non checkpoint 8 3738 2602029796 步骤二:随便开始一个事务 SQL> update jj_10 set name='aa' where id=20; 已更新 1 行。 步骤三:把步骤二中的表脱机: SQL> alter tablespace jj_ts_1 offline; 表空间已更改。 步骤四:此时再去查看资料视图: SQL> select * from v$sysstat where name='physical writes non checkpoint'; STATISTIC# NAME CLASS VALUE STAT_ID ---------- ------------------------------ ---------- ---------- ---------- 67 physical writes non checkpoint 8 3759 2602029796 **比较后发现,检查点无关写从3738增加到3759. 为了观察到通过检查点队列的写,把检查点频率调的高一点: alter system set log_checkpoint_timeout=10; 步骤一: SQL> select * from v$sysstat where name='physical writes' or name='physical writes non checkpoint'; STATISTIC# NAME CLASS VALUE STAT_ID ---------- ------------------------------ ---------- ---------- ---------- 62 physical writes 8 5822 1190468109 67 physical writes non checkpoint 8 3829 2602029796 用physical writes减去physical writes non checkpoint所得到的结果,将近似于通过检查点队列的写.为什么说近似于呢?因为oracle内部会有很多写,比如说控制文件的写操作,也会被记录进physical writes 资料. 步骤二:发布更新命令 SQL> update jj_10 set name='aa' where id=20; 已更新 1 行。 步骤三:观察块是否变的不脏. SQL> select dirty,status from v$bh where file#=7 and block#=406 and status='xcur'; D STATUS - ------- N xcur 步骤四:在块变的不脏后,马上查看资料视图. SQL> select * from v$sysstat where name='physical writes' or name='physical writes non checkpoint'; STATISTIC# NAME CLASS VALUE STAT_ID ---------- ------------------------------ ---------- ---------- ---------- 62 physical writes 8 5851 1190468109 67 physical writes non checkpoint 8 3832 2602029796 **可以看到检查点无关写多了3个字节,这3个字节和我们的更新声明没有关系.我们的更新声明更新了几十个字节.这3个字节应该是属于oracle内部的一些写操作,我们的更新声明,所产生的脏块,是通过检查点队列写出的.physical writes 多了很多. 1,增量检查点, 增量检查点所涉及的主要概念,是一个队列一个进程.队列是检查点队列,进程是CKPT进程.CKPT进程有两项任务,一个是在一定的时机触发DBWR并告知DBWR的Target RBA,另一个任务是每3秒一次将DBWR的写进度更新到控制文件中.CKPT的这两个任务合在一起,叫做--增量检查点.通常所说的触发增量检查点,是指CKPT进程通知DBWR刷新脏块这个操作. 在10g中把 log_checkpoint_to_alert设置为真,可以在告警日志中观察到增量检查点的触发.在9I中看不到增量检查点,可以看到其他检查点的触发信息. 观察增量检查点: 步骤1: SQL> alter system set log_checkpoints_to_alert=true; 系统已更改。 步骤2:将增量检查点的切换频率定为300秒. SQL> alter system set log_checkpoint_timeout=300;[单位是秒] 系统已更改。 步骤3:查看告警日志中的增量检查点信息. ... Incremental checkpoint up to RBA [0x2b9.747.0], current log tail at RBA [0x2b9.848.0] Mon Mar 03 14:51:40 2008 Incremental checkpoint up to RBA [0x2b9.855.0], current log tail at RBA [0x2b9.876.0] Mon Mar 03 14:56:43 2008 Incremental checkpoint up to RBA [0x2b9.877.0], current log tail at RBA [0x2b9.8f0.0] Mon Mar 03 15:01:43 2008 Incremental checkpoint up to RBA [0x2b9.8f5.0], current log tail at RBA [0x2b9.d70.0] Mon Mar 03 15:06:43 2008 Incremental checkpoint up to RBA [0x2b9.d74.0], current log tail at RBA [0x2b9.fd9.0] Mon Mar 03 15:11:44 2008 ... 注:Incremental checkpoint(增量检查点的意思)/第1个RBA(增量检查点发生时当前的检查点位置)/第2个RBA(检查点发生时的当前的on disk rba); 可以看到每5分钟一次检查点. 另外可以通过v$kcccp视图观察当前的检查点位置. SQL> select CPDRT,to_char(CPLRBA_SEQ,'xxxx')||'.'||to_char(CPLRBA_BNO,'xxxxx')||'.'||CPLRBA_BOF "Low 16",CPLRBA_SEQ||'.'||CPLRBA_BNO||'.'||CPLRBA_BOF "Low RBA",CPODR_SEQ||'.'||CPODR_BNO||'.'||CPODR_BOF "On disk RBA",CPODS,CPODT,CPHBT from x$kcccp where cphbt<>0; CPDRT Low 16 Low RBA On disk RBA CPODS CPODT CPHBT ---------- -------------------- --------------- --------------- ---------------- -------------------- ---------- 26 2ba. 9d.0 698.157.0 698.307.0 2363076 03/03/2008 15:23:07 648336376 为了便于观察:Low 16 是Low RBA 的16进制. 注:在x$kcccp中看到的是DBWR的写进度.当把 log_checkpoints_to_alert这个参数设置为true后,可以在告警日志中看到增量检查点的触发信息. 2,日志切换时的检查点. 当发生日志切换时,也会触发检查点.在数据库并不繁忙的情况下,日志切换的检查点并不急于完成.之所以在日志切换的时候触发一次检查点,是为了保证重做日志文件所对应的脏块都被写进磁盘文件.如果写脏块的速度比较慢,日志文件循环一圈后,又该覆盖此日志文件时,而此日志文件的检查点还没有完成,那么覆盖操作将等待.等待事件名:log file switch(checkpoint incomplete).如果出现该等待事件,解决方法:1,可以增加日志文件组的数量.2,观察下增量检查点的间隔时间.如果是因为增量检查点间隔时间太长,导致积攒的脏块过多.可以把增量检查点参数设置的频繁点. 日志切换检查点除了会触发DBWR写脏块外,CKPT进程还要将切换时的SCN写进数据文件头和控制文件中的数据库信息节,还有数据文件节.另外还要将新的联机重做日志文件中第一条重做记录的RBA写进数据文件头. 日志切换检查点写进数据文件头的SCN,可以通过v$datafile_header视图查看. 日志切换检查点写进控制文件中数据库信息节的SCN,可以通过v$database查看. 日志切换检查点写进控制文件中的数据文件节中的SCN,可以通过v$datafile查看. 先把log_checkpoints_to_alert这个参数设置为真,以便可以在告警日志中看到日志切换检查点的相关信息. alter system set log_checkpoints_to_alert=true; 实验:验证下当触发了日志切换检查点后, 数据文件头,控制文件中的日志切换检查点信息都是什么: 步骤一:查看当前数据文件头的SCN SQL> select checkpoint_change#,checkpoint_time,checkpoint_count from v$datafile_header; CHECKPOINT_CHANGE# CHECKPOINT_TIM CHECKPOINT_COUNT ------------------ -------------- ---------------- 2372527 03-3月 -08 646 2372527 03-3月 -08 609 2372527 03-3月 -08 646 ...... 已选择11行。 步骤二:查看当前控制文件中的数据库信息节的日志切换检查点信息 SQL> select checkpoint_change# from v$database; CHECKPOINT_CHANGE# ------------------ 2372527 步骤三:查看当前控制文件中的数据文件节中的日志切换检查点信息 SQL> select checkpoint_change#,checkpoint_time,last_change#,last_time,substr(name,1,30) from v$datafile; CHECKPOINT_CHANGE# CHECKPOINT_TIM LAST_CHANGE# LAST_TIME SUBSTR(NAME,1,30) ------------------ -------------- ------------ -------------- ------------------------------------------- 2372527 03-3月 -08 E:\ORACLE\PRODUCT\10.2.0\ORADA 2372527 03-3月 -08 E:\ORACLE\PRODUCT\10.2.0\ORADA 2372527 03-3月 -08 E:\ORACLE\PRODUCT\10.2.0\ORADA ...... 已选择11行。
步骤四:查看当前SCN SQL> select dbms_flashback.get_system_change_number from dual; GET_SYSTEM_CHANGE_NUMBER ------------------------ 2373997 步骤五:手动触发日志切换检查点 SQL> alter system switch logfile; 系统已更改。 步骤六:查看日志切换后的数据文件头的SCN SQL> select checkpoint_change#,checkpoint_time,checkpoint_count from v$datafile_header; CHECKPOINT_CHANGE# CHECKPOINT_TIM CHECKPOINT_COUNT ------------------ -------------- ---------------- 2372527 03-3月 -08 646 2372527 03-3月 -08 609 2372527 03-3月 -08 646 ...... 已选择11行。 步骤七:查看日志切换后控制文件中的数据库信息节的日志切换检查点信息 SQL> select checkpoint_change# from v$database; CHECKPOINT_CHANGE# ------------------ 2372527 步骤八:查看日志切换后控制文件中的数据文件节中的日志切换检查点信息 SQL> select checkpoint_change#,checkpoint_time,last_change#,last_time,substr(name,1,30) from v$datafile; CHECKPOINT_CHANGE# CHECKPOINT_TIM LAST_CHANGE# LAST_TIME SUBSTR(NAME,1,30) ------------------ -------------- ------------ -------------- ----------------------------------------------- 2372527 03-3月 -08 E:\ORACLE\PRODUCT\10.2.0\ORADA 2372527 03-3月 -08 E:\ORACLE\PRODUCT\10.2.0\ORADA 2372527 03-3月 -08 E:\ORACLE\PRODUCT\10.2.0\ORADA ...... 已选择11行。 **由于普通测试机的I/O并不繁忙,看到的数据很有可能是没有发生变化的,这个时候可以查看告警日志.发现 Mon Mar 03 19:50:35 2008 Beginning log switch checkpoint up to RBA [0x2c0.2.10], SCN: 2374009 Thread 1 advanced to log sequence 704 Current log# 9 seq# 704 mem# 0: E:\LOG9A.RDO 此时的日志切换还未完成,数据文件头的日志切换的检查点和控制文件的日志切换检查点还没来的急更新.少等一会就会完成.oracle会根据机器的繁忙程度来决定什么时候完成日志切换的检查点.通常如果机器比较繁忙,oracle趋向于更急切的完成日志切换检查点. 少等一会再次查看告警日志: Mon Mar 03 19:50:35 2008 Beginning log switch checkpoint up to RBA [0x2c0.2.10], SCN: 2374009 Thread 1 advanced to log sequence 704 Current log# 9 seq# 704 mem# 0: E:\LOG9A.RDO Mon Mar 03 19:53:58 2008 Completed checkpoint up to RBA [0x2c0.2.10], SCN: 2374009 可以发现除了beginning log switch chenkpoint外,多了一个completed checkpoint.日志切换的检查点到此才真正的完成.由于我的实验环境并不繁忙,oracle拖了3分钟才去真正的完成日志切换检查点. 此时再查看日志切换后的数据文件头的SCN SQL> select checkpoint_change#,checkpoint_time,checkpoint_count from v$datafile_header; CHECKPOINT_CHANGE# CHECKPOINT_TIM CHECKPOINT_COUNT ------------------ -------------- ---------------- 2374009 03-3月 -08 647 2374009 03-3月 -08 610 2374009 03-3月 -08 647 ...... 再查看日志切换后控制文件中的数据库信息节的日志切换检查点信息 SQL> select checkpoint_change# from v$database; CHECKPOINT_CHANGE# ------------------ 2374009 再查看日志切换后控制文件中的数据文件节中的日志切换检查点信息 SQL> select checkpoint_change#,checkpoint_time,last_change#,last_time,substr(name,1,30) from v$datafile; CHECKPOINT_CHANGE# CHECKPOINT_TIM LAST_CHANGE# LAST_TIME SUBSTR(NAME,1,30) ------------------ -------------- ------------ -------------- ---------------------------------------------- 2374009 03-3月 -08 E:\ORACLE\PRODUCT\10.2.0\ORADA 2374009 03-3月 -08 E:\ORACLE\PRODUCT\10.2.0\ORADA 2374009 03-3月 -08 E:\ORACLE\PRODUCT\10.2.0\ORADA ...... ****从结果可以看出日志切换时的SCN是2373997,而视图中所显示的2374009比2373997大了12.这是因为手动查看SCN和手动切换日志这两个命令间有个时间差.(忽略不计).由此可以证明,在日志切换时,CKPT写进数据文件和控制文件中的SCN,是切换命令开始时的SCN. 在日志切换时,被写进数据文件头的并不只有SCN信息,还有RBA信息.这个RBA是新的连机重做日志文件第一条重做记录的RBA.根据告警日志中的信息,此处是RBA [0x2c0.2.10].上面所介绍的几个视图中,没有显示RBA信息.我们可以通过转储查看到这个RBA. 转储命令如下: SQL> alter session set events 'immediate trace name file_hdrs level 10'; 会话已更改。 转储数据文件头的结果: DATA FILE #1: (name #7) E:\ORACLE\PRODUCT\10.2.0\ORADATA\ONE10G\SYSTEM01.DBF ... Checkpointed at scn: 0x0000.00243979 03/03/2008 19:50:35 [这些信息对应v$datafile_header] thread:1 rba
0x2c0.2.10) ... ****在转储文件中的每个数据文件相关信息中,都可以找到如上两行,这其中检查点SCN和时间戳,我们都已经在视图中看到了. RBA信息,告警日志中显示的有,上述3个视图中并未显示出来. 转储控制文件的结果: 这是控制文件中 数据库信息节中的日志切换检查点信息: *************************************************************************** DATABASE ENTRY *************************************************************************** ... Database checkpoint: Thread=1 scn: 0x0000.00243979[这些信息对应v$database] ... 这是控制文件中的数据文件记录节,可以看到日志切换检查点SCN. DATA FILE #1: (name #7) E:\ORACLE\PRODUCT\10.2.0\ORADATA\ONE10G\SYSTEM01.DBF ... Checkpoint cnt:647 scn: 0x0000.00243979 03/03/2008 19:50:35 [这些信息对应v$datafile] ... ****在控制文件中,只记录日志切换时的SCN,不记录RBA. 3,完全检查点. 完全检查点,将会写出所有的脏块,完全检查点发生时,将不能有新的脏块产生,直到完全检查点完成,以非shutdown abort关闭数据库时就会发生完全检查点,还有就是手动发布命令:alter system checkpoint; 完全检查点也将会在数据文件头,控制文件中数据库信息节,数据文件节中写入当前SCN. 查看告警日志信息如下: Mon Mar 03 15:38:11 2008 Beginning global checkpoint up to RBA [0x2ba.285.10], SCN: 2363568 Completed checkpoint up to RBA [0x2ba.285.10], SCN: 2363568 *****小结:日志切换所触发的检查点,1,要通知DBWR写脏块.2,要向数据文件头和控制文件中写入切换时的SCN.3,把新的连机重做日志的第一重做记录的RBA写进数据文件头.****** 为什么要记录写入时的SCN和RBA呢?? 如果现在数据文件头和控制文件中的SCN是2374009,假如说现在发生了介质故障,数据库宕机,将两星期前备份的某一个数据文件还原过来覆盖当前的已损坏的数据文件.这个备份的数据文件头SCN是2370000,当启动数据库时,oracle会发现数据文件头的SCN和控制文件中的SCN 不匹配,此时会要求完成介质恢复.当 recover datafile 时,oracle会根据数据文件头所记载的RBA,到相应的日志文件中寻找重做信息,进行恢复.
源文档 <http://space.itpub.net/?uid-13095417-action-viewspace-itemid-199237>
|
||||||||||||||||||||
|
|
检查点SCN深入研究(1)
一、检查点概述 大多数关系型数据库都采用“在提交时并不强迫针对数据块的修改完成”而是“提交时保证修改记录(以重做日志的形式)写入日志文件”的机制,来获得性能的优势。这句话的另外一种描述是:当用户提交事务,写数据文件是“异步”的,写日志文件是“同步”的。这就可能导致数据库实例崩溃时,内存中的DB_Buffer中的修改过的数据,可能没有写入到数据块中。数据库在重新打开时,需要进行恢复,来恢复DB Buffer中的数据状态,并确保已经提交的数据被写入到数据块中。检查点是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。 要了解这个检查点,首先要知道checkpoint queu概念,检查点发生后,触发dbwn,CKPT获取发生检查点时对应的SCN,通知DBWn要写到这个SCN为止, dbwr写dirty buffer是根据buffer在被首次modify的时候的时间的顺序写出,也就是buffer被modify的时候会进入一个queue(checkpoint queue),dbwr就根据queue从其中批量地写到数据文件。由于这里有一个顺序的关系,所以dbwr的写的进度就是可衡量的,写到哪个buffer的时候该buffer的首次变化时候的scn就是当前所有数据文件block的最新scn,但是由于无法适时的将dbwr的进度记录下来,所以oracle选择了一些策略。其中就包括ckpt进程的检查点和心跳。 但oracle考虑到检查点scn的间隔还是太大了,因为检查点的触发条件有限,周期可能比较长,有些情况下比如检查点需要5分钟才触发,那这个时候系统crash再重新启动就意味着很可能系统需要5分钟才能启动。 于是oracle采用了一个心跳的概念,以3秒的频率将dbwr写的进度反应到控制文件中,这样系统crash重新启动的时候将从更近的一个时间点开始恢复。 再这里同样需要说明的一点是dbwr并不是只有当检查点发生的时候才写,它大约有10几种条件触发写操作 所以这个问题,我们需要理解的是oracle为什么要这么做? oracle的目的就是缩短崩溃恢复时间! oracle如何缩短恢复时间? 1:检查点机制 2:心跳机制 oracle为什么不适时的将dbwr写进度反应到文件中? 适时反应成本太高!3秒种是一个合适的值,可以接受,代价不高又能大大缩短崩溃后恢复时间。 检查点发生以后,CKPT进程检查checkpoint queue(也就是脏块链表)是否过长,如果是,则触发DBWn,将一部分脏块写入数据文件,从而缩短checkpoint queue。 checkpoint发生时,一方面通知dbwr进行下一批写操作,(dbwr写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。)另一方面,oracle采用了一个心跳的概念,以3秒的频率将dbwr写的进度反应到控制文件中,也就是把dbwr当前刚写完的dirty buffer对应的scn写入数据文件头和控制文件,这就是检查点scn。 这个3秒和增量检查点不是一个概念,3秒只是在控制文件中,ckpt进程去更新当前dbwr写到哪里了,这个对于ckpt进程来说叫heartbeat,heartbeat是3秒一次,3秒可以看作不停的检查并记录检查点执行情况(DBWR的写进度)。 检查点发生之后数据库的数据文件、控制文件处于一致状态的含义是不需要进行介质恢复,只表示数据文件头一致,但是并不表示数据文件内容一致,因为数据文件内容可能在没有发生检查点的其他情况下的dbwr写数据文件,这样数据文件内容就不一致,若掉电需要进行崩溃恢复。 二、触发的条件 这里需要明白两个概念“完全检查点和增量检查点”的区别。 增量检查点(incremental checkpoint) oracle8之前,那时候没有chekpoint queue,也没有增量的概念,dirty buffer的写出是无顺的,就是冻结所有dml等候所有dirty buffer被写出。后来随着数据库规模的扩展和buffer cache的不断增大,oracle意识到这个机制已经满足不了需要,所以提出增量检查点的概念,建立了checkpoint queue,让dirty buffer header根据首次变化时候的顺序排列在queue里面。这样dbwr只要顺着queue的顺序写,而其他进程不必等候dbwr的写操作完成就可以继续。 自从有了checkpoint queue之后,检查点就成为一个短暂的动作,就是通知dbwr你要继续写dirty buffer到当前检查点发生时候的scn,然后将当前dbwr刚写完的dirty buffer对应的scn,写进数据文件和控制文件【增量检查点时不写数据文件头】(比如日志切换这种动作引起的检查点动作等)。然后检查点动作就结束了。剩下的工作就交给DBWn了,检查点进程也不必等候dbwr的完成。 ckpt进程通知dbwr之后并不需要等待dbwr写到当前这个检查点对应的时间点。所以ckpt可以将已经完成的最后一个检查点scn写到控制文件和数据文件(可能是上一个,也可能是上上个,总之dbwr完成了哪个算哪个)。这样本次需要写进数据文件的dirty buffer可能在下一次检查点发生的时候已经写完了,这样下一次检查点发生的时候就把本次的检查点scn更新到控制文件和数据文件。 在oracle 8之前,没有ckpt queue,只有LRU list,而LRU list里面的Dirty Buffer是不按时间顺序排列的,所以checkpoint时都会做一个full thread checkpoint,将LRU list中的所有buffer写到数据文件。 在oracle8i以后,当发生FULL CHECKPOINT时,oracle只是获取系统当前的SCN,然后将这个SCN之前的脏数据块写入磁盘,后续的DML脏数据块继续入队,他并不是保证整个缓冲区没有脏块,只是保证此检查点发生之前这段距离间没有脏块,而在checkpoint点之后的DML可以正常操作。 oracle8以后推出了incremental checkpoint的机制,在以前的版本里每checkpoint时都会做一个full thread checkpoint,这样的话所有脏数据会被写到磁盘,巨大的i/o对系统性能带来很大影响。为了解决这个问题,oracle引入了checkpoint queue机制,每一个脏块会被移到检查点队列里面去,按照low rdb(第一次对此块修改对应的redo block address)来排列,靠近检查点队列尾端的数据块的low rba值是最小的,而且如果这些赃块被再次修改后它在检查点队列里的顺序也不会改变,这样就保证了越早修改的块越早写入磁盘。每隔3秒钟ckpt会去更新控制文件和数据文件,记录checkpoint执行的情况。 在运行的Oracle数据中,有很多事件、条件或者参数来触发检查点。比如 当已通过正常事务处理或者立即选项关闭例程时;(shutdown immediate或者Shutdown normal;) 当通过设置初始化参数LOG_CHECKPOINT_INTERVAL、LOG_CHECKPOINT_TIMEOUT和FAST_START_IO_TARGET强制时; 当数据库管理员手动请求时;(ALter system checkpoint) alter tablespace ... offline; 每次日志切换时;(alter system switch logfile) 需要说明的是,alter system switch logfile也将触发完全检查点的发生。 alter database datafile ... offline不会触发检查点进程。 如果是单纯的offline datafile,那么将不会触发文件检查点,只有针对offline tablespace的时候才会触发文件检查点,这也是为什么online datafile需要media recovery而online tablespace不需要。 对于表空间的offline后再online这种情况,最好做个强制的checkpoint比较好。 上面几种情况,将触发完全检查点,促使DBWR将检查点时刻前所有的脏数据写入数据文件。 另外,一般正常运行期间的数据库不会产生完全检查点,下面很多事件将导致增量检查点,比如: 在联机热备份数据文件前,要求该数据文件中被修改的块从DB_Buffer写入数据文件中。所以,发出这样的命令: ALTER TABLESPACE tablespace_name BIGEN BACKUP & end backup;也将触发和该表空间的数据文件有关的局部检查点;另外, ALTER TABLESPACE tablespace_name READ ONLY; ALTER TABLESPACE tablespace_name OFFLINE NORMAL; 等命令都会触发增量检查点。 注意: 每隔三秒也会触发检查点,但是并没有被oracle正式作为一种检查点的触发方式列入文档,并且这个3秒是记录dbwr进度而不是通知dbwr写。 这是三秒触发的检查点与其它条件触发检查点不同的地方。 三:关于low cache rba与on disk rba的理解:
简单说:low cache rba就是CKPT记录的DBWR写的进度。 on disk rba就是LGWR的写进度。 如果数据库carsh,low cache rba是恢复的起点,on disk rba是恢复的终点。 阐述一下:dbwr成功写完后并不把此刻scn信息写到控制文件中,只有CKPT才更新控制文件和数据文件头,dbwr只要成功将dirty data写入数据文件就是成功,CKPT只要能将最新DBWR写完的SCN更新到控制文件和数据文件头就算成功。但是由于CKPT进程不是实时更新dbwr写完的scn到控制文件中,而是采用每3妙更新一次的策略,因此最后有ckpt进程写进控制文件的scn信息有可能不是当前dbwr刚刚写完的scn值。这点应该注意,也就是说dbwr写的进度与ckpt进程更新控制文件的进度是不同的。
关于检查点的一点具体应用讨论: Commit成功后,数据还会丢失吗? 对于Oracle来说,用户所做的DML操作一旦被提交,则先是在database buffer cache中进行修改,同时在修改之前会将数据的前镜像保存在回滚段中,然后将修改之前和修改之后的数据都写入到redo log buffer中,当接收到commit命令之后,则redo log buffer开始写redo log file,并且记录此时的scn,当redo log file写完了之后,表示这次事务提交操作已经确认被数据库记录了,只有当redo log file写成功了,才会给用户Commit completed的成功字样。而对于Database buffer cache中的dirty buffer则会等待触发DBWn才写入,但是如果此时断电,则数据已经被记录到了redo log file中,系统在重新启动的时候,会自动进行嵌滚和回滚来保证数据的一致。所以,只要是commit成功的了,数据不会丢失! 数据库发生一次DBWn,是否将所有buffer cache中的dirty buffer都写入,还是先将脏队列中的数据写入? 这话看起来有道理,但实际上,dbwr在写的时候又不断地在产生dirty buffer ,所以说检查点发生的时候是期望把该时间点之前的所有脏缓冲区写入数据文件。 所有的buffer,不在LRU list上就在dirty list上, dbwr写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。 所以说要是dbwr将dirty list也好,lru list上的也好,要实现全部写入,都是一个现实系统中很难存在的现象。dirty总是在不断的产生,dbwr总是在不断地写,增量检查点发生的时候也并不意味着一定要更新数据文件头,检查点开始的时候只表示该次检查点结束的时候要更新数据文件头的话数据文件头具有该时间点的一致性。 data block里面不是也有SCN吗?和文件头里面的SCN有什么关系?什么时候被更新?代表的是是什么含义? data block里面的SCN是当block被更改的时候的SCN 而数据文件有那么多block,自然不同的block有不同的SCN block中存在block SCN和ITL中的commit SCN block SCN又在块头和块位都有,若不一致意味着block损坏(热碑可能出现这个情况,需要从redo log中拷贝回来,若是正在修改的过程中由于进程死掉则pmon负责清理。若由于一些以外发生这样的不一致的情况,则查询的时候出现1578错误,当然该错误号也可能是物理磁盘损坏,这里表示逻辑的损坏!) 这个头和尾的SCN的检查时机跟这两个参数有关: db_block_checking boolean FALSE db_block_checksum boolean FALSE 该2参数信息请查阅http://tahiti.oracle.com 而ITL中的commit SCN则跟consistent gets and delay block cleanout有关 数据文件头的SCN是检查点发生时更新的,代表着当恢复的时候从这个SCN点开始在log file中寻找redo开始做恢复。 看下面的操作! ___________________________________________________________ sys@DBAP01>select max(ktuxescnw*power(2,32)+ktuxescnb)from x$ktuxe;
MAX(KTUXESCNW*POWER(2,32)+KTUX
------------------------------
52211024
已用时间: 00:00:00.00
sys@DBAP01>alter system checkpoint;
系统已更改。
已用时间: 00:00:00.06
sys@DBAP01>select CHECKPOINT_CHANGE# from v$database;
CHECKPOINT_CHANGE#
------------------
52211055
已用时间: 00:00:00.00
sys@DBAP01>select max(ktuxescnw*power(2,32)+ktuxescnb)from x$ktuxe;
MAX(KTUXESCNW*POWER(2,32)+KTUX
------------------------------
52211053
已用时间: 00:00:00.00 sys@DBAP01> 怎么解释这个现象? 解答:x$ktuxe计算出来的是已经结束的最新的事务的commit scn,所以可小于当前系统scn。检查点scn自然也小于当前系统scn。但是检查点scn和x$ktuxe计算出来的大小却倚赖于系统状况了。 current scn是系统当前所产生的最大scn,可能是当前未结束事务所产生的scn。在9i的dbms_flashback.get_system_number可以得到这个值,这个值应该是大于等于x$ktuxe SCN (这个view记录的是当前数据库结束事务的最大scn) 关于SCN的一些理解: 在控制文件,数据文件头,数据块,日志文件头,日志文件change vector中都有SCN,但其作用各不相同。 1、数据文件头中包含了该数据文件的checkpoint SCN,表示给数据文件最近一次执行检查点操作时的SCN. 2、日志文件头中包含了low scn,next scn,表示给日志文件包含有从low scn到next scn的redo record. 3、控制文件中包含了每个数据文件的checkpoint SCN,stop SCN,每个日志文件的low scn,next scn。控制文件中checkpoint scn同数据文件头中checkpoint scn相同,除非数据文件被手工替换掉.控制文件中的low scn,next scn同日志文件中low scn和next scn相同。 在数据库正常运行时,控制文件中对应数据文件的stop SCN都是最大值. 在正常关闭数据库的情况下,在关闭前会执行一次检查点工作当oracle会将数据缓冲区上的内容全部写回到磁盘中,然后更新控制文件中对应数据文件的stop SCN,使其等于checkpoint SCN。 但在异常当机的情况下,由于最后一次检查点未进行或进行中间被中止,因而在控制文件,就存在部分的数据文件stop SCN为最大值。 在数据库重新启动后,会检查控制文件中对应每个数据文件的stop SCN,如果stop SCN不等于控制文件中对应每个数据文件的checkpoint SCN,就会使用日志文件redo从checkpoint SCN开头到stop SCN为止的全部数据库操作. 在定位到底使用哪个日志文件的时候,并不是用数据文件中的low scn去框,也不是只要在日志文件的low scn and next scn之间就利用该日志文件。而是在数据文件头中有RBA的记录,RBA包含了日志序号、block number、slot number。这样可以直接定位到日志文件(归档日志文件)和具体的位置。 在确定了哪个数据文件须redo后,oracle会比较change vector(向量)中的SCN和数据文件数据块中的SCN,如果change vector的SCN小于数据块的scn,则跳过此change vector,否则redo数据块中ITL中还有SCN,但它的作用是用于产生一致性读快照。 commit的时候加一,其他很多时候也会加1,只要数据库发生了变化都会增加。 很多时候,能否举一些例子 dml一发生即使没有提交也会增加scn, job进程一样产生scn,只要对数据库中文件发生任何的改变都有可能产生scn, SCN: system change number, not system commit number .也就是系统发生变化所产生的一个时间点标志。不是提交的标志,只是因为提交也是系统的变化之一而已。
这句话我应该更准确第表达一下: 如果一个dml导致产生事务,则会产生一个scn。这个意思是说 如果一个事务包含多个dml,则只有第一个初始产生事务的dml产生scn,提交的时候又是一个scn。 如果一个事务只有一个dml,那么看起来就是dml产生一个scn,提交或者回滚产生一个scn。 所以可以把结论定义为事务的开始和事务的结束都会导致SCN的增加,同一个block上在一个事务中连续发生255个DML后scn也会增加。 检查点的发生和日志的关系: 解答: 检查点的发生,跟写日志文件是没有必然联系的。 检查点发生,通知DBWR写数据文件,写完后ckpt更新控制文件和数据文件头。 当DBWR写数据块的时候若发现数据块的相关RDBA (位于日志文件的位置)的log block还没有被写入日志文件,则在dbwr写块之前必须通知lgwr把log buffer中日志写入日志文件。 关于检查点等待事件: 有些事件的产生必须等待检查点的完成,才能开始数据库的其它操作: 日志文件切换就是其中一个事件,日志切换必须等待检查点完成。 log file switch (checkpoint incomplete)这个等待事件本身也说明,日志切换时产生的检查点是需要等待的,这个日志文件所对应脏块全部写完后,检查点进程更新控制文件和数据头,然后这个检查点才能算完成。 也就是说日志切换必须等待检查点完成,而检查点在等待DBWn完成。 这种等待DBWn完成的检查点,最后一步写入控制文件和数据文件头的SCN,肯定是DBWn完成的最后一块的SCN。 检查点为什么要等待dbwr完成后才进行切换(log switch)? log switch时,是不能立即switch到active状态的日志文件的,此时切换进程必须等待。active表示该log group还没有完成归档(归档模式下)或者该log group有进行instance recovery需要用到的日志。所以当checkpoint发生时,如果dbwr还没有写完它该写完的dirty buffers(该checkpoint时间点以前产生的dirty buffers,靠scn判断),则该log group处于active状态,不会进行日志切换,当然也不会发生日志文件被覆盖的问题了。 如果没有设置archive log,在检查点发生后,发生log switch一个轮回,log file是否会被覆盖掉? 当检查点发生后,会触发lgwr,lgwr会把此时SCN以前在redo buffer中的所有操作写到redo log file,同时lgwr也会触发dbwr进程,dbwr也开始把此刻以前database buffer中的dirty buffer队列中的操作写入data file。 其实检查点发生后,就是lgwr和dbwr写buffer到磁盘文件的过程,但是两者的读写速度时不同的,dbwr写buffer到数据文件的过程相对较慢,因为dbwr写过程是一个随机读取存储的过程。Lgwr写buffer到redo文件的过程比dbwr要快很多,因为lgwr是顺序读取写入的。 由于以上lgwr和dbwr写操作的速度不同,就产生了一个等待问题。即当lgwr 轮循一圈后,要进行日志切换,覆盖redo log file,但是此时dbwr还没有写完,那么lgwr就会出现等待,oracle也会hang在那里,同时alter文件中会提示一个相应的提示checkpoint not complete。等检查点完成后数据库自动恢复正常。 当log switch时,会触发检查点,标记检查点时,DBWR要把log file中covered by the log being checkpointed的数据写入到数据文件上,如果Dbwr没有写完,那么前一个logfile是不能被覆盖的。因此必须等检查点完毕,也可以说是将要被覆盖的日志相关的数据块全部写入数据文件后,该日志文件才能被覆盖! 如果这种情况出现,alert文件中会记录checkpoint not complete事件,这通常表明你的dbwr写入过慢或者logfile组数过少或log file太小。
源文档 <http://space.itpub.net/?uid-15142212-action-viewspace-itemid-589327>
|
||||||||||||||||||||
|
|
CHECKPIONT与SCN 一、CHECKPIONT分为三类: 1)局部CHECKPIONT: 单个实例执行数据库所有数据文件的一个CHECKPIONT操作,属于此实例的全部脏缓存区写入数据文件。 触发命令:SQL>alter system checkpoint local; 这条命令显示的触发一个局部检查点。 2)全局CHECKPIONT: 所有实例(对应并行数据服务器)执行数据库所有数据文件的一个CHECKPIONT操作,属于此实例的全部脏缓存区写入数据文件。 触发命令:SQL>alter system checkpoint global; 这条命令显示的触发一个全局检查点。 3)文件CHECKPIONT: 所有实例需要执行数据文件集的一个检查点操作,如使用热备份命令alter tablespace USERS begin backup,或表空间脱机命令alter tablespace USERS offline,将执行属于USERS表空间的所有数据文件的一个检查点操作。 二、CHECKPIONT处理步骤: 1)获取实例状态队列: 实例状态队列是在实例状态转变时获得,ORACLE获得此队列以保证CHECKPIONT执行期间,数据库处于打开状态; 2)获取当前CHECKPIONT信息: 获取CHECKPIONT记录信息的结构,此结构包括当前CHECKPIONT时间、活动线程、进行CHECKPIONT处理的当前线程、日志文件中恢复截止点的地址信息; 3)缓存区标识: 标识所有脏缓存区,当CHECKPIONT找到一个脏缓存区就将其标识为需要进行刷新,标识的脏缓存区由系统进程DBWR进行写操作,将脏缓存区的内容写入数据文件; 4)脏缓存区刷新: DBWR进程将所有脏缓存区写入磁盘后,设置一标志,标识已完成脏缓存区至磁盘的写入操作。系统进程LGWR与CKPT进程将继续进行检查,直至DBWR进程结束为止; 5)更新控制文件与数据文件。 注:控制文件与数据文件头包含CHECKPIONT结构信息。 三、CHECKPIONT事件 CHECKPIONT事件是数据库的一个很重要的内部事件,只有了解它的运行机制,才能很好的掌握数据库的内部运行,才能很好的掌握备份与恢复,也才能在紧急的时候解决必要的问题…… CHECKPIONT事件的触发,将使得数据库将已经修改的数据(脏数据)写到磁盘,同时还将修改控制文件和数据库头,同步它们的scn号,它的触发条件是: 当发生日志组切换的时候 当符合LOG_CHECKPOINT_TIMEOUT,LOG_CHECKPOINT_INTERVAL,fast_start_io_target,fast_start_mttr_target参数设置的时候 当运行ALTER SYSTEM SWITCH LOGFILE的时候 当运行ALTER SYSTEM CHECKPOINT的时候 当运行alter tablespace XXX begin backup,end backup的时候 当运行alter tablespace ,datafile offline的时候; 运行alter tablespace、datafile offline的时候,它们存在着一定的区别: alter datafile offline: 在offline、online的时候,系统将不会修改所有datafile的scn alter tablespace offline: offline的事件,就会修改scn号;在online的时候,系统也将修改该ts下的所有datafile的scn 这正是为什么online datafile需要recovery,而online tablespace就不需要。 其实当检查点发生的时候,CKPT获取发生检查点时对应的SCN,通知DBWn要写到这个SCN为止,CKPT将最近一次(可能是上次也可能是上上次)DBWn成功完成写Dirty Buffer时对应的SCN更新到控制文件和数据文件头 (增量检查点时不写数据文件头)。至此检查点事件完成。剩下的工作就交给DBWn了。期间,CKPT检查checkpoint queue(也就是脏块链表)是否过长,如果是,则触发DBWn,DBWn将开始工作,他将一部分脏块写入数据文件,从而缩短checkpoint queue。但是为了恢复过程的迅速,CKPT进程以3秒的频率将DBWn写的进度反应到控制文件中,就是CKPT进程每三秒钟向控制文件写一次DBWn的执行情况,也就是把DBWn当前刚写完的dirty buffer对应的scn 写入数据文件头和控制文件。因此,可以看出,CKPT更新数据文件和控制文件,不是使用当前检查点的scn,而是使用上一次检查点过程中DBWn进程成功写完成dirty buffer队列中某个block 对应的scn 。 如果在DBWn写dirty buffer时候,发生掉电,则恢复过程肯定是:首先从控制文件中找到,上次检查点发生后最后成功写入那个block块对应的scn往后进行恢复。也就是CKPT进程在掉电前那最后一个三秒钟轮回,向控制文件写如的scn为恢复的前界限,往后进行恢复。 检查点是一个数据库事件,它把修改数据从高速缓存写入磁盘,并更新控制文件和数据文件。 在两种情况下,文件头中的检查点信息(获取当前检查点信息时)将不做更新: 1)数据文件不处于热备份方式,此时ORACLE将不知道操作系统将何时读文件头,而备份拷贝在拷贝开始时必须具有检查点SCN;ORACLE在数据文件头中保留一个检查点的记数器,在正常操作中保证使用数据文件的当前版本,在恢复时防止恢复数据文件的错误版本;即使在热备份方式下,计数器依然是递增的;每个数据文件的检查点计数器,也保留在控制文件相对应数据文件项中。 2)检查SCN小于文件头中的检查点SCN的时候,这表明由检查点产生的改动已经写到磁盘上,在执行全局检查点的处理过程中,如果一个热备份快速检查点在更新文件头时,则可能发生此种情况。应该注意的是,ORACLE是在实际进行检查点处理的大量工作之前捕获检查SCN的,并且很有可能被一条象热备份命令 alter tablespace USERS begin backup进行快速检查点处理时的命令打断。 ORACLE在进行数据文件更新之前,将验证其数据一致性,当验证完成,即更新数据文件头以反映当前检查点的情况;未经验证的数据文件与写入时出现错误的数据文件都被忽略;如果日志文件被覆盖,则这个文件可能需要进行介质恢复,在这种情况下,ORACLE系统进程DBWR将此数据文件脱机。 检查点算法描述: 脏缓存区用一个新队列链接,称为检查点队列。对缓存区的每一个改动,都有一个与其相关的重做值。检查点队列包含脏的日志缓存区,这些缓存区按照它们在日志文件中的位置排序,即在检查点队列中,缓存区按照它们的低重做值进行排序。需要注意的是,由于缓存区是依照第一次变脏的次序链接到队列中的,所以,如果在缓存区写出之前对它有另外的改动,链接不能进行相应变更,缓存区一旦被链接到检查点队列,它就停留在此位置,直到将它被写出为止。 ORACLE系统进程DBWR在响应检查点请求时,按照这个队列的低重做值的升序写出缓存区。每个检查点请求指定一个重做值,一旦DBWR写出的缓存区重做值等于或大于检查点的重做值,检查点处理即完成,并将记录到控制文件与数据文件。 由于检查点队列上的缓存区按照低重做值进行排序,而DBWR也按照低重做值顺序写出检查点缓存区,故可能有多个检查点请求处于活动状态,当DBWR写出缓存区时,检查位于检查点队列前端的缓存区重做值与检查点重做值的一致性,如果重做值小于检查点队列前缓存区的低重做值的所有检查点请求,即可表示处理完成。当存在未完成的活动检查点请求时,DBWR继续写出检查点缓存区。 算法特点: 1)DBWR能确切的知道为满足检查点请求需要写那些缓存区; 2)在每次进行检查点写时保证指向完成最早的(具有最低重做值的)检查点; 3)根据检查点重做值可以区别多个检查点请求,然后按照它们的顺序完成处理 四、SCN的管理方式 Oracle对SCN的管理,分为单节点和RAC两种方式: 1.单节点的instance中 单节点的instance中,SCN值存在SGA区,由system commit number latch保护。任何进程要得到当前的SCN值,都要先得到这个latch。 2.RAC/OPS环境中 Oracle通过排队机制(Enqueue)实现SCN在各并行节点之间的顺序增长。 具体有两种方法: Lamport算法: 又称面包房算法,先来先服务算法。跟很多银行采用的排队机制一样。客户到了银行,先领取一个服务号。一旦某个窗口出现空闲,拥有最小服务号的客户就可以去空闲窗口办理业务。 Commit广播算法: 一有commit完成,最新的SCN就广播到所有节点中。 上述两种算法可以通过调整初始化参数max_commit_propagation_delay来切换。在多数系统 (除了Compaq Tur64 Unix)中,该参数的默认值都是700厘秒(centisecond),采用Lamport算法。如果该值小于100厘秒,Oracle就采用广播算法,并且记录在alert.log文件中。 五、SCN的种类 Commit SCN 当用户提交commit命令后,系统将当前scn赋给该transaction。这些信息都反映在redo buffer中,并马上更新到redo log 文件里。 Offline SCN 除了System tablespace以外的任何表空间,当我们执行SQL>alter tablespace … offline normal命令时,就会触发一个checkpoint,将内存中的dirty buffer写入磁盘文件中。Checkpoint完成后,数据文件头会更新checkpoint scn和offline normal scn值。其中数据库文件头的checkpoint scn值可通过查询列x$kccfe.fecps得到。 如果执行SQL>alter tablespace …offline命令时采用temporary或 immediate选项,而不用normal选项时,offline normal scn会被设成0。这样当数据库重启后通过resetlog方式打开时,该表空间就无法再改回在线状态。 Checkpoint SCN 当数据库内存的脏数据块(dirty blocks)写到各数据文件中时,就发生一次checkpoint。数据库的当前checkpoint scn值存在x$kccdi.discn中。Checkpoint scn在数据库恢复中起着至关重要的作用。无论你用何种办法恢复数据库,只有当各个数据库文件的checkpoint scn都相同时,数据库才能打开。 虽然参数“_allow_resetlogs_corruption”可以在checkpoint scn不一致时强制打开数据库,但是这样的数据库在open后必须马上作全库的export,然后重建数据库并import数据。 Resetlog SCN 数据库不完全恢复时,在指定时间点后的scn都无法再应用到数据库中。Resetlog时的scn就被设成当前数据库scn,redo log也会被重新设置。 Stop SCN Stop scn记录在数据文件头上。当数据库处在打开状态时,stop scn被设成最大值0xffff.ffffffff。在数据库正常关闭过程中,stop scn被设置成当前系统的最大scn值。在数据库打开过程中,Oracle会比较各文件的stop scn和checkpoint scn,如果值不一致,表明数据库先前没有正常关闭,需要做恢复。 High and Low SCN Oracle的Redo log会顺序纪录数据库的各个变化。一组redo log文件写满后,会自动切换到下一组redo log文件。则上一组redo log的high scn就是下一组redo log的low scn。 在视图v$log_history中,sequence#代表redo log的序列号,first_change#表示当前redo log的low scn,列next_change#表示当前redo log的high scn。 SQL> col recid format 9999 SQL> col requence# format 9999 SQL> col first_change# format 9,999,999,999,999 SQL> col next_change# format 9,999,999,999,999 SQL> select recid,sequence#,first_change#,next_change# from v$log_history where rownum<6; RECID SEQUENCE# FIRST_CHANGE# NEXT_CHANGE# ----- ---------- ------------------ ------------------ 484 484 1,928,645,840,091 1,928,645,840,436 485 485 1,928,645,840,436 1,928,645,840,636 486 486 1,928,645,840,636 1,928,778,045,209 487 487 1,928,778,045,209 1,929,255,480,725 488 488 1,929,255,480,725 1,930,752,214,033 六、SCN号与oracle数据库恢复的关系 SCN号与oracle数据库恢复过程有着密切的关系,只有很好地理解了这层关系,才能深刻地理解恢复的原理,从而才能很好地解决这方面的问题。 SCN与CHECKPOINT CKPT进程在checkpoint发生时,将当时的SCN号写入数据文件头和控制文件,同时通知DBWR进程将数据块写到数据文件。 CKPT进程也会在控制文件中记录RBA(redo block address),以标志Recovery需要从日志中哪个地方开始。与checkpoint相关的SCN号有四个,其中三个存在控制文件中,一个存放在数据文件头中。 这四个分别是: 1.System Checkpoint SCN 当checkpoint完成后,ORACLE将System Checkpoint SCN号存放在控制文件中。 我们可以通过下面SQL语句查询: select checkpoint_change# from v$database; 2.Datafile Checkpoint SCN 当checkpoint完成后,ORACLE将Datafile Checkpoint SCN号存放在控制文件中。 我们可以通过下面SQL语句查询所有数据文件的Datafile Checkpoinnt SCN号。 select name,checkpoint_change# from v$datafile; 3.Start SCN号 ORACLE将Start SCN号存放在数据文件头中。 这个SCN用于检查数据库启动过程是否需要做media recovery. 我们可以通过以下SQL语句查询: select name,checkpoint_change# from v$datafile_header; 4.End SCN号 ORACLE将End SCN号存放在控制文件中。 这个SCN号用于检查数据库启动过程是否需要做instance recovery. 我们可以通过以下SQL语句查询: select name,last_change# from v$datafile; 在数据库正常运行的情况下,对可读写的,online的数据文件,该SCN号为NULL. 试验内容如下: 在执行检查点进程之前SCN号如下: a.System Checkpoint SCN SQL>select checkpoint_change# from v$database; CHECKPOINT_CHANGE# ------------------ 4609061 b.Datafile Checkpoint SCN SQL>select name,checkpoint_change# from v$datafile; NAME CHECKPOINT_CHANGE# ------------------- ------------------ D:\BOCO\OPENVIEW\ORADATA\OPENVIEW\user01.dbf 4609061 c.Start SCN SQL>select name,checkpoint_change# from v$datafile_header; NAME CHECKPOINT_CHANGE# ------------------- ------------------ D:\BOCO\OPENVIEW\ORADATA\OPENVIEW\user01.dbf 4609061 d.End SCN SQL>select name,last_change# from v$datafile; 未选定行 执行alter system checkpoint后的SCN号如下: a.System Checkpoint SCN SQL>select checkpoint_change# from v$database; CHECKPOINT_CHANGE# ------------------ 4609630 b.Datafile Checkpoint SCN SQL>select name,checkpoint_change# from v$datafile; NAME CHECKPOINT_CHANGE# ------------------- ------------------ D:\BOCO\OPENVIEW\ORADATA\OPENVIEW\user01.dbf 4609630 Start SCN SQL>select name,checkpoint_change# from v$datafile_header; NAME CHECKPOINT_CHANGE# ------------------- ------------------ D:\BOCO\OPENVIEW\ORADATA\OPENVIEW\user01.dbf 4609630 End SCN SQL>select name,last_change# from v$datafile; 未选定行 SCN不连续原因可能如下: 1.当发生日志组切换的时候 2.当符合LOG_CHECKPOINT_TIMEOUT,LOG_CHECKPOINT_INTERVAL,fast_start_io_target,fast_start_mttr_target参数设置的时候 3.当运行ALTER SYSTEM SWITCH LOGFILE的时候 4.当运行ALTER SYSTEM CHECKPOINT的时候 5.当运行alter tablespace XXX begin backup,end backup的时候 6.当运行alter tablespace ,datafile offline的时候; 七、SCN号与数据库启动 在数据库启动过程中,当System Checkpoint SCN、Datafile Checkpoint SCN和Start SCN号都相同时,数据库可以正常启动,不需要做media recovery.三者当中有一个不同时,则需要做media recovery。 如果在启动的过程中,End SCN号为NULL,则需要做instance recovery。ORACLE在启动过程中首先检查是否需要media recovery,然后再检查是否需要instance recovery。 八、SCN号与数据库关闭 如果数据库的正常关闭的话,将会触发一个checkpoint,同时将数据文件的END SCN号设置为相应数据文件的Start SCN号。 当数据库启动时,发现它们是一致的,则不需要做instance recovery。在数据库正常启动后,ORACLE会将END SCN号设置为NULL。 如果数据库异常关闭的话,则END SCN号将为NULL. 九、为什么需要System checkpoint SCN号与Datafile Checkpoint SCN号? 为什么ORACLE会在控制文件中记录System checkpoint SCN号的同时,还需要为每个数据文件记录Datafile Checkpoint SCN号? 原因有二: 1.对只读表空间,其数据文件的Datafile Checkpoint SCN、Start SCN和END SCN号均相同。这三个SCN在表空间处于只读期间都将被冻结。 2.如果控制文件不是当前的控制文件,则System checkpoint会小于Start SCN或END SCN号。记录这些SCN号,可以区分控制文件是否是当前的控制文件。 十、Recovery database using backup controlfile 以下条件需要使用using backup controlfile 1)使用备份控制文件 2)重建resetlogs控制文件,如果重建立noresetlogs不必要使用using backup controlfile 当有一个Start SCN号超过了System Checkpoit SCN号时,则说明控制文件不是当前的控制文件,因此在做recovery时需要采用using backup controlfile。这是为什么需要记录System Checkpoint SCN的原因之一。 这里需要一提的是,当重建控制文件的时候,System Checkpoint SCN为0,Datafile Checkpoint SCN的数据来自于Start SCN。 根据上述的描述,此时需要采用using backup controlfile做recovery。 十一、alter database open resetlog 指定RESETLOGS将重设当前LOG sequence number为1,抛弃所有日志信息。 以下条件需要使用resetlog 1)在不完全恢复(介质恢复) 2)使用备份控制文件 使用resetlogs打开数据库后无必完整地备份一次数据库。 十二、create controlfile resetlogs/noresetlogs 1)用noresetlogs重建控制文件时,控制文件中 datafile checkpoint来自online logs中的current log头 2)用resetlogs重建控制文件时,控制文件中datafile checkpoint来自各数据文件头。
源文档 <http://blog.sina.com.cn/s/blog_490cd3080100htvm.html>
|
||||||||||||||||||||
|
|
一、检查点概述 大多数关系型数据库都采用"在提交时并不强迫针对数据块的修改完成"而是"提交时保证修改记录(以重做日志的形式)写入日志文件"的机制,来获得性能的优势。这句话的另外一种描述是:当用户提交事务,写数据文件是"异步"的,写日志文件是"同步"的。这就可能导致数据库实例崩溃时,内存中的DB_Buffer 中的修改过的数据,可能没有写入到数据块中。数据库在重新打开时,需要进行恢复,来恢复DB Buffer 中的数据状态,并确保已经提交的数据被写入到数据块中。检查点是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。 要了解这个检查点,首先要知道checkpoint queue概念,检查点发生后,触发dbwr,CKPT获取发生检查点时对应的SCN,通知DBWr要写到这个SCN为止, dbwr 写dirty buffer 是根据 buffer 在被首次修改的时候的时间的顺序写出,也就是 buffer被修改的时候会进入一个queue (checkpoint queue),dbwr 就根据queue从其中批量地写到数据文件。 由于这里有一个顺序的关系,所以 dbwr的写的进度就是可衡量的,写到哪个buffer的时候该buffer的首次变化时候的scn就是当前所有数据文件block的最新scn,但是由于无法适时的将dbwr的进度记录下来,所以oracle 选择了一些策略。 其中就包括ckpt进程的检查点和心跳。 检查点发生以后,CKPT进程检查checkpoint queue(也就是脏块链表)是否过长,如果是,则触发DBWr,将一部分脏块写入数据文件,从而缩短checkpoint queue。 checkpoint 发生时,一方面通知dbwr进行下一批写操作,(dbwr 写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。)另一方面,oracle 采用了一个心跳的概念,以3秒的频率将dbwr 写的进度反应到控制文件中,也就是把dbwr当前刚写完的dirty buffer对应的scn 写入数据文件头和控制文件,这就是检查点scn。 这个3秒和增量检查点不是一个概念,3秒只是在控制文件中,ckpt 进程去更新当前dbwr写到哪里了,这个对于ckpt 进程来说叫 heartbeat ,heartbeat是3秒一次,3秒可以看作不停的检查并记录检查点执行情况(DBWR的写进度)。 检查点发生之后数据库的数据文件、控制文件处于一致状态的含义是不需要进行介质恢复,只表示数据文件头一致,但是并不表示数据文件内容一致,因为数据文件内容可能在没有发生检查点的其他情况下的dbwr写数据文件,这样数据文件内容就不一致,若掉电需要进行崩溃恢复。 二、SCN SCN(System Chang Number)作为oracle中的一个重要机制,在数据恢复、Data Guard、Streams复制、RAC节点间的同步等各个功能中起着重要作用。理解SCN的运作机制,可以帮助你更加深入地了解上述功能。 1、系统检查点scn 当一个检查点动作完成后,Oracle就把系统检查点的SCN存储到控制文件中。 select checkpoint_change# from v$database 2、数据文件检查点scn 当一个检查点动作完成后,Oracle就把每个数据文件的scn单独存放在控制文件中。 select name,checkpoint_change# from v$datafile 3、启动scn Oracle把这个检查点的scn存储在每个数据文件的文件头中,这个值称为启动scn,因为它用于在数据库实例启动时,检查是否需要执行数据库恢复。 select name,checkpoint_change# from v$datafile_header 4、终止scn 每个数据文件的终止scn都存储在控制文件中。 select name,last_change# from v$datafile 在正常的数据库操作过程中,所有正处于联机读写模式下的数据文件的终止scn都为null. 5、在数据库运行期间的scn值 在数据库打开并运行之后,控制文件中的系统检查点、控制文件中的数据文件检查点scn和每个数据文件头中的启动scn都是相同的。控制文件中的每个数据文件的终止scn都为null. 在安全关闭数据库的过程中,系统会执行一个检查点动作,这时所有数据文件的终止scn都会设置成数据文件头中的那个启动scn的值。在数据库重新启动的时候,Oracle将文件头中的那个启动scn与数据库文件检查点scn进行比较,如果这两个值相互匹配,oracle接下来还要比较数据文件头中的启动 scn和控制文件中数据文件的终止scn。如果这两个值也一致,就意味着所有数据块多已经提交,所有对数据库的修改都没有在关闭数据库的过程中丢失,因此这次启动数据库的过程也不需要任何恢复操作,此时数据库就可以打开了。当所有的数据库都打开之后,存储在控制文件中的数据文件终止scn的值再次被更改为 null,这表示数据文件已经打开并能够正常使用了。 三、事务过程 我们再看下oracle事务中的数据变化是如何写入数据文件的: 1、 事务开始; 2、 在buffer cache中找到需要的数据块,如果没有找到,则从数据文件中载入buffer cache中; 3、 事务修改buffer cache的数据块,该数据被标识为“脏数据”,并被写入log buffer中; 4、 事务提交,LGWR进程将log buffer中的“脏数据”写入redo log file中; 5、 当发生checkpoint,CKPT进程更新所有数据文件的文件头中的信息,DBWr进程则负责将Buffer Cache中的脏数据写入到数据文件中。 经过上述5个步骤,事务中的数据变化最终被写入到数据文件中。但是,一旦在上述中间环节时,数据库意外宕机了,在重新启动时如何知道哪些数据已经写入数据文件、哪些没有写呢(同样,在DG、streams中也存在类似疑问:redo log中哪些是上一次同步已经复制过的数据、哪些没有)?SCN机制就能比较完善的解决上述问题。 SCN是一个数字,确切的说是一个只会增加、不会减少的数字。正是它这种只会增加的特性确保了Oracle知道哪些应该被恢复、哪些应该被复制。 总共有4种SCN:系统检查点(System Checkpoint)SCN、数据文件检查点(Datafile Checkpoint)SCN、结束SCN(Stop SCN)、开始SCN(Start SCN)。其中前面3中SCN存在于控制文件中,最后一种则存在于数据文件的文件头中。 在控制文件中,System Checkpoint SCN是针对整个数据库全局的,因而只存在一个,而Datafile Checkpoint SCN和Stop SCN是针对每个数据文件的,因而一个数据文件就对应在控制文件中存在一份Datafile Checkpoint SCN和Stop SCN。在数据库正常运行期间,Stop SCN(通过视图v$datafile的字段last_change#可以查询)是一个无穷大的数字或者说是NULL。 在一个事务提交后(上述第四个步骤),会在redo log中存在一条redo记录,同时,系统为其提供一个最新的SCN(通过函数dbms_flashback.get_system_change_number可以知道当前的最新SCN),记录在该条记录中。如果该条记录是在redo log被清空(日志满做切换时或发生checkpoint时,所有变化日志已经被写入数据文件中),则其SCN被记录为redo log的low SCN。以后在日志再次被清空前写入的redo记录中SCN则成为Next SCN。 当日志切换或发生checkpoint(上述第五个步骤)时,从Low SCN到Next SCN之间的所有redo记录的数据就被DBWn进程写入数据文件中,而CKPT进程则将所有数据文件(无论redo log中的数据是否影响到该数据文件)的文件头上记录的Start SCN(通过视图v$datafile_header的字段checkpoint_change#可以查询)更新为Next SCN,同时将控制文件中的System Checkpoint SCN(通过视图v$database的字段checkpoint_change#可以查询)、每个数据文件对应的Datafile Checkpoint(通过视图v$datafile的字段checkpoint_change#可以查询)也更新为Next SCN。但是,如果该数据文件所在的表空间被设置为read-only时,数据文件的Start SCN和控制文件中Datafile Checkpoint SCN都不会被更新。 四、心跳 在Oracle中有一个事件叫Heartbeat,这个词在很多地方被提及,并且有着不同的含义(比如RAC中),我们这里要讨论的是CKPT的Heartbeat机制。 Oracle通过CKPT进程每3秒将Heartbeat写入控制文件,以减少故障时的恢复时间(这个我们后面再详细阐述)。 我们可以通过如下方法验证这个过程。 1.首先在系统级启用10046时间跟踪 并重新启动数据库使之生效 [oracle@jumper oracle]$ sqlplus "/ as sysdba" SQL*Plus: Release 9.2.0.4.0 - Production on Thu Jan 19 09:24:04 2006 Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. Connected to:Oracle9i Enterprise Edition Release 9.2.0.4.0 - ProductionWith the Partitioning optionJServer Release 9.2.0.4.0 - Production SQL> alter system set event='10046 trace name context forever,level 12' scope=spfile; System altered. SQL> shutdown immediate; Database closed. Database dismounted. ORACLE instance shut down. SQL> startup ORACLE instance started. Total System Global Area 114365800 bytes Fixed Size 451944 bytesVariable Size 50331648 bytes Database Buffers 62914560 bytes Redo Buffers 667648 bytes Database mounted. Database opened. SQL> exit Disconnected from Oracle9i Enterprise Edition Release 9.2.0.4.0 - ProductionWith the Partitioning optionJServer Release 9.2.0.4.0 - Production 2.检查bdump目录下生成的跟踪文件 目录在$ORACLE_HOME/admin/$ORACLE_SID/bdump目录下,每个后台进程都会生成一个跟踪文件。 [oracle@jumper bdump]$ ls 20050424_alert_conner.log conner_arc0_2569.trc conner_dbw0_2559.trc conner_reco_2567.trc alert_conner.log conner_arc1_2571.trc conner_lgwr_2561.trc conner_smon_2565.trca.sql conner_ckpt_2563.trc conner_pmon_2557.trc 3.检查CKPT进程的跟踪文件 我们可以很容易的发现CKPT进程每3秒都对控制文件进行一次写入 [oracle@jumper bdump]$ tail -f conner_ckpt_2563.trc WAIT #0: nam='rdbms ipc message' ela= 2994710 p1=300 p2=0 p3=0WAIT #0: nam='control file parallel write' ela= 2442 p1=3 p2=3 p3=3WAIT #0: nam='rdbms ipc message' ela= 2995171 p1=300 p2=0 p3=0WAIT #0: nam='control file parallel write' ela= 2586 p1=3 p2=3 p3=3WAIT #0: nam='rdbms ipc message' ela= 2994962 p1=300 p2=0 p3=0WAIT #0: nam='control file parallel write' ela= 2582 p1=3 p2=3 p3=3WAIT #0: nam='rdbms ipc message' ela= 2995020 p1=300 p2=0 p3=0WAIT #0: nam='control file parallel write' ela= 2455 p1=3 p2=3 p3=3WAIT #0: nam='rdbms ipc message' ela= 2995188 p1=300 p2=0 p3=0WAIT #0: nam='control file parallel write' ela= 2412 p1=3 p2=3 p3=3WAIT #0: nam='rdbms ipc message' ela= 2995187 p1=300 p2=0 p3=0WAIT #0: nam='control file parallel write' ela= 2463 p1=3 p2=3 p3=3WAIT #0: nam='rdbms ipc message' ela= 2995095 p1=300 p2=0 p3=0WAIT #0: nam='control file parallel write' ela= 2448 p1=3 p2=3 p3=3 4.检查控制文件的变更 通过2次dump控制文件,比较其trace文件输出可以比较得到不同之处,我们发现,Oracle仅仅更新了Heartbeat这个数值。 [oracle@jumper udump]$ sqlplus "/ as sysdba" SQL*Plus: Release 9.2.0.4.0 - Production on Wed Jan 18 22:44:10 2006 Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. Connected to:Oracle9i Enterprise Edition Release 9.2.0.4.0 - ProductionWith the Partitioning optionJServer Release 9.2.0.4.0 - Production SQL> alter session set events 'immediate trace name CONTROLF level 10'; Session altered. SQL> exitDisconnected from Oracle9i Enterprise Edition Release 9.2.0.4.0 - ProductionWith the Partitioning optionJServer Release 9.2.0.4.0 - Production[oracle@jumper udump]$ sqlplus "/ as sysdba" SQL*Plus: Release 9.2.0.4.0 - Production on Wed Jan 18 22:44:18 2006 Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. Connected to:Oracle9i Enterprise Edition Release 9.2.0.4.0 - ProductionWith the Partitioning optionJServer Release 9.2.0.4.0 - Production SQL> alter session set events 'immediate trace name CONTROLF level 10' ; Session altered. SQL> exitDisconnected from Oracle9i Enterprise Edition Release 9.2.0.4.0 - ProductionWith the Partitioning optionJServer Release 9.2.0.4.0 - Production [oracle@jumper udump]$ lsconner_ora_21896.trc conner_ora_21898.trc[oracle@jumper udump]$ diff conner_ora_21896.trc conner_ora_21898.trc 1c1< /opt/oracle/admin/conner/udump/conner_ora_21896.trc---> /opt/oracle/admin/conner/udump/conner_ora_21898.trc14c14< Unix process pid: 21896, image: oracle@jumper.hurray.com.cn (TNS V1-V3)---> Unix process pid: 21898, image: oracle@jumper.hurray.com.cn (TNS V1-V3)16c16< *** SESSION ID9.813) 2006-01-18 22:44:14.314---> *** SESSION ID9.815) 2006-01-18 22:44:21.569 63c63< heartbeat: 579991793 mount id: 3191936000---> heartbeat: 579991796 mount id: 3191936000 [oracle@jumper udump]$
源文档 <http://apps.hi.baidu.com/share/detail/24548269>
|
||||||||||||||||||||
|
|
ORACLE启动原理
Checkpoint 很多人都把checkpoint的概念给复杂化了,其实checkpoint这个数据库概念引入的真正意义就是用来减少在数据库恢复过程中所花的时间(instance recovery),那么checkpoint是由谁来做的呢?我们都知道数据库中有个CKPT进程,这是个可选进程,但是真正执行检查点的任务并不是由ckpt来完成的,而是ckpt在更新控制文件和数据文件头的有关信息后,通知DBWn进程,产生一个检查点,在产生检查点的时候,DBWn进程会将buffer cache中的脏数据(当前online redo log对应的脏数据),写入我们的数据文件当中。这个时候如果数据库此时崩溃(比如我们做个shutdown abort),那么在进行实例恢复的时候就可以不需要当前online redo log的内容了,会很快就做完。因此ckpt进程只是个辅助进程,他的任务更多的是用来在系统做checkpoint的时候更新控制文件和数据文件头中的信息。其实在oracle 8i的时候呢,ckpt的任务一般都是由lgwr进程来完成,到了8i以后,随着CKPT进程的引入,lgwr的工作负担就减轻了很多(commit的速度加快了) 那么如何来产生检查点呢? 有三种方法,可以通过 1.alter system checkpoint 2.alter system switch logfile 3.DBWn进程写出脏块 SCN 在Oracle中理解为一个内部同步时钟,是系统改变号的缩写(system change number),在Oracle数据库中我们可以通过dbms_flashback包来查询当前系统的改变号: select dbms_flashback.get_system_change_number from dual;一般来 讲SCN主要是用来标识数据库所做的所有改变,这个SCN的改变是只能前进,不能回退,除非我们打算重建库,数据库中的SCN永远不会归0,一般来说SCN的前进触发是由commit来进行的,除了这些据我观察每隔3秒种系统也都会刷新一次SCN. 需要注意的是: 1.CKPT一定是是在checkpoint发生的时候将数据库当前的SCN更新入数据库文件头和控制文件当中,同时DBWn进程将buffer cache中的脏数据块(dirty block)写到数据文件当中(这个脏数据也一定是当前online redo log保护的那一部分)。 2.同时CKPT进程还会在控制文件当中记录(redo block address)RBA,这个地址用来标志恢复的时候需要从日志中的那个位置开始。 在Oracle数据库中和checkpoint相关的SCN总共有4个 1.System checkpoint SCN (存在于控制文件) 在系统执行checkpoint后,Oracle会更新当前控制文件中的System checkpoint SCN。 我们可以通过 select checkpoint_change# from v$database: 来查看 2.Datafile checkpoint SCN (存在于控制文件) 由于控制文件中记录了Oracle中各个数据库文件的位置和信息,其中当然也包括了Datafile checkpoint SCN,因此在执行checkpoint的时候,Oracle还会去更新控制文件中所记录的各个数据文件的datafile checkpoint SCN. 我们可以通过 select checkpoint_change# from v$datafile; 来查看 3.Start SCN (存在于各个数据文件头) 在执行checkpoint时,Oracle会更新存放在各个实际的数据文件头的Start SCN(注意绝对不会是控制文件中),这个SCN存在的目的是用于检查数据库启动过程中是否需要做media recovery(介质恢复) 我们可以通过 select checkpoint_change# from v$datafile_header; 4.End SCN(存在于控制文件) 最后一类SCN,End SCN他也是记录在控制文件当中,每一个所记录的数据文件头都有一个对应的End SCN,这个End SCN一定是存在于控制文件当中。这个SCN存在的绝对意义主要是用来去验证数据库启动过程中是否需要做instance recovery。我们可以通过 select name,last_change# from v$datafile 那么其实在数据库正常运行的情况下,对于read/write的online 数据文件这个SCN号为#FFFFFF(NULL). 下面来聊一聊SCN号于数据库的启动 1.在数据库的启动过程中,当System Checkpoint SCN=Datafile Checkpoint SCN=Start SCN的时候,Oracle数据库是可以正常启动的,而不需要做任何的media recovery。而如果三者当中有一个不同的话,则需要做media recovery 2.那什么时候需要做instance recovery呢?其实在正常open数据库的时候,oracle会将记录在控制文件中的每一个数据文件头的End SCN都设置为#FFFFFF(NULL),那么如果数据库进行了正常关闭比如(shutdown or shutdown immediate)这个时候,系统会执行一个检查点,这个检查点会将控制文件中记录的各个数据文件头的End SCN更新为当前online数据文件的各个数据文件头的Start SCN,也就是End SCN=Start SCN,如果再次启动数据库的时候发现二者相等,则直接打开数据库,并再次将End SCN设置为#FFFFFF(NULL),那么如果数据库是异常关闭,那么heckpoint就不会执行,因此再次打开数据库的时候End SCN<>Start SCN这个时候就需要做实例恢复。 说了那么多更新SCN操作什么的,这个更新操作到底是由谁做的呢?其实刚才已经说过了,就是我们的CKPT进程,他不仅仅会更新SCN,而且还会通知DBWn做他的事情。 再说一下System Checkpoint SCN和Datafile Checkpoint SCN,这两个SCN都是记录在控制文件当中的。但是这两个SCN有什么作用呢? logzgh有段论述,我自己的想了一下,还是学习一下他的结论: 1.对只读表空间,其数据文件的Datafile Checkpoint SCN、Start SCN和END SCN号均相同。这三个SCN在表空间处于只读期间都将被冻结。 2.如果控制文件不是当前的控制文件(其实就是说,想比当前redo log的SCN来讲,控制文件已经过时了),则System checkpoint SCN会小于Start SCN(Start SCN是来自实际的数据文件头,有比较依据)。记录这些SCN号,可以区分控制文件是否是当前的控制文件。当有一个Start SCN(从当前各个在线数据文件中获得)号超过了System Checkpoit SCN号时,则说明控制文件不是当前的控制文件,因此在做recovery时需要采用using backup controlfile。这是为什么需要记录SystemCheckpoint SCN的原因之一。 当我们重建控制文件的时候,重建方式分两种(resetlogs 和 noresetlogs) 1.使用resetlogs选项时,System Checkpoint SCN为被归为0,而其中记录的各个数据文件的Datafile Checkpoint SCN则来自于Start SCN(也就是说可能会从冷备份的数据文件的数据文件头中获取)。根据上述的描述,此时需要采用using backup controlfile做recovery. 因此情况是 System Checkpoint SCN=0 < Start SCN = Datafile Checkpoint SCN 2.使用noresetlogs选项时,有一个前提就是:一定要有online redo log的存在。否则就要使用resetlogs选项。 这个时候控制文件重建好时,其system checkpoint SCN=Datafile Checkpoint SCN=Lastest Checkpoint SCN in online redo log,我们可以看到Datafile Checkpoint SCN并没有从Start SCN中读取。而是读取了最新的日志文件中的SCN作为自己的数据。此时重建的控制文件在恢复中的作用跟最新的控制文件类似,System Checkpoint SCN(已经读取最新的redo log的checkpoint SCN信息)可能会>Start SCN (因为数据文件可能会从冷备份中恢复),恢复时就不需要加using backup controlfile子句了 关于backup controlfile的补充:backup controlfile只有备份时刻的archive log信息,并没有DB crash时刻的archive log信息,所以并不会自动应用online redo log,而是提示找不到序号为Lastest Archive log sequence + 1 的archive log,尽管你可以手动指定online redo log来实现完全恢复,但因为一旦使用了using backup controlfile子句,Oracle就视为不完全恢复,必须open resetlogs! 实际上,假如你有旧的控制文件又不想resetlogs,那很简单,使用旧的控制文件mount然后 backup to trace ,然后手工创建控制文件,使用 reuse database ... noresetlogs .这样就可以recover database 自动恢复并open database 而不用 resetlogs 了
源文档 <http://blog.csdn.net/zengkefeng/archive/2010/02/02/5279869.aspx>
|
||||||||||||||||||||
|
|
|


