一、检查点概述
大多数关系型数据库都采用“在提交时并不强迫针对数据块的修改完成”而是“提交时保证修改记录(以重做日志的形式)写入日志文件”的机制,来获得性能的优势。这句话的另外一种描述是:当用户提交事务,写数据文件是“异步”的,写日志文件是“同步”的。这就可能导致数据库实例崩溃时,内存中的DB_Buffer 中的修改过的数据,可能没有写入到数据块中。数据库在重新打开时,需要进行恢复,来恢复DB Buffer 中的数据状态,并确保已经提交的数据被写入到数据块中。检查点是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。
IXDBA.NET社区论坛要了解这个检查点,首先要知道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 数据中,有很多事件、条件或者参数来触发检查点。比如
l 当已通过正常事务处理或者立即选项关闭例程时;(shutdown immediate或者Shutdown normal;)
l 当通过设置初始化参数LOG_CHECKPOINT_INTERVAL、LOG_CHECKPOINT_TIMEOUT 和FAST_START_IO_TARGET 强制时;
l 当数据库管理员手动请求时;(ALter system checkpoint)
l alter tablespace ... offline;
l 每次日志切换时;(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 写入数据文件中。所以,发出这样的命令:
l ALTER TABLESPACE tablespace_name BIGEN BACKUP & end backup; 也将触发和该表空间的数据文件有关的局部检查点;另外,
l ALTER TABLESPACE tablespace_name READ ONLY;
l 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,但其作用各不相同。
数据文件头中包含了该数据文件的checkpoint SCN,表示给数据文件最近一次执行检查点操作时的SCN.
日志文件头中包含了low scn,next scn,表示给日志文件包含有从low scn到next scn的redo record.
控制文件中包含了每个数据文件的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太小。
检查点发生时,出现日志切换,但是dbwr还没有写完,是否会覆盖redo log file,如果此时掉电,dbwr挂起,会出现丢失数据吗?
答:不会覆盖redo文件,要等待dbwr写完才覆盖。或者说要等待检查点完成才覆盖。
如果DBWn正在写的脏块是指对应到即将被覆盖的那个日志文件的,那么,因为在这些操作完成之前,不可能有覆盖这件事发生,假设你预料的掉电发生了,不会有什么问题,实例恢复时的前滚从刚才准备覆盖的那个日志文件开始。
如果正在写的脏块是指对应到刚刚被写满的那个日志文件的,肯定一时半会也写不完,日志切换也不会等它,如果切换成功后dbwr挂了,后面的写脏块操作估计也还没完成,但是,刚写满的那个文件并没有被覆盖,也不会有任何问题。
alter systen switch logfile会触发完全检查点;但是为什么,日志切换以后检查点只能记录到上一次归档日志产生的时间呢?而不是现在归档日志产生的时间呢?
因为这时的checkpoint enqueue队列中,也就是脏块队列中脏块还不够多,还不足以触发DBWn写脏块。所以,内存里需要写入的脏块所对应的redo还存在于上一个redo log里,这时你去看该redo log的status为active。
下面操作日志中出现当前redo log的status为current,而上一个redo log的status为active就说明了这一切。上一个redo log的status为active正是说明在上一个redo log中还存在未写入datafile的block所对应的redo。
SQL> create table gaojf8 as select * from all_objects;
Table created
SQL> insert into gaojf3 select * from gaojf3;
29630 rows inserted
SQL> /
59260 rows inserted
SQL> commit;
Commit complete
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119126928 08/08/2006 00:28:38 1 14 2 16 0200000000000000 0 0 3 1 3 1 14 8796117861680 08/02/2006 02:29:36 0 13 cicro 08/02/2006 02:33:50
SQL> alter system switch logfile;
System altered
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119126928 08/08/2006 00:28:38 1 14 2 16 0200000000000000 0 0 3 1 3 2 15 8796117861680 08/02/2006 02:29:36 0 14 cicro 08/02/2006 02:33:50
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- -------------------- 421A54D0 0 1 1 15 8796119126928 08/08/2006 00:28:38 1 14 2 16 0200000000000000 0 0 3 1 3 2 15 8796117861680 08/02/2006 02:29:36 0 14 cicro 08/02/2006 02:33:50
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119128114 08/08/2006 00:35:51 1 15 2 16 0200000000000000 0 0 3 1 3 3 16 8796117861680 08/02/2006 02:29:36 0 15 cicro 08/02/2006 02:33:50
从上面试验中可以看到,完全检查点正在执行,还没有执行完毕。因此,切换日志前后察看x$kccrt,看到的RTCKP_SCN, RTCKP_TIM没有发生变化。等检查点执行完毕后(也就是检查点触发的dbwr执行完写操作后),rtckp_scn, rtckp_tim才发生变化。
原文地址:http://www.ixdba.net/article/04/359.html
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/24005010/viewspace-694408/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/24005010/viewspace-694408/