我的一个总结:检查点SCN深入研究

    技术2022-05-12  24

    一、检查点概述

    大多数关系型数据库都采用 在提交时并不强迫针对数据块的修改完成 而是 提交时保证修改记录(以重做日志的形式)写入日志文件 的机制,来获得性能的优势。这句话的另外一种描述是:当用户提交事务,写数据文件是 异步 的,写日志文件是 同步 的。这就可能导致数据库实例崩溃时,内存中的 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 总是在不断地写 , 增量检查点发生的时候也并不意味着一定要更新数据文件头,检查点开始的时候只表示该次检查点结束的时候要更新数据文件头的话数据文件头具有该时间点的一致性

    IXDBA.NET社区论坛

    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 挂了,后面的写脏块操作估计也还没完成,但是,刚写满的那个文件并没有被覆盖,也不会有任何问题。

     

    因此不会出现数据丢失!

    当一个很大的 dml 发生时,用户在 commit 后,需要将 redo log buffer 中的脏数据写入 redo log file 中。如果在写的过程中,发现一个 redo log file 写不下的话,需要写另外一个 redo log file ,这时应该触发 checkpoint ,接着触发 DBWn ,将脏数据写入 datafile ,这时发生掉电,导致 DBWR 失败。这时其实就可以说 commit 失败了。以上所述其实就是 commit 没有提交成功。

    IXDBA.NET技术社区

     

    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

    -------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------

    421A 54D0          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

    -------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------

    421A 54D0          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

    -------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------

     

    421A 54D0          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

    IXDBA.NET技术社区

    -------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------

    421A 54D0          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 才发生变化。


    最新回复(0)