1、本期学习内容为 SCN,RedoLog 和 Checkpoint 相关的一些基础概念、平常不理解的东西。
- 2、redo log 的作用
- 数据库异常关机(比如突然断电,shutdown abort: 它会立即关闭数据库,等同于断电)之后,这时已经 commit 的事务已经记录到 online redo log 中,下次启动数据库时,Oracle 进行恢复操作,将 online redo log 中的事务操作调入内存中,进行相应操作后将数据记入到数据文件中,数据操作完成。
- 对于没有 commit 而已经写入数据文件或回退段的数据,也要进行回滚操作,将数据恢复到 rollback 的状态,使数据文件和控制文件恢复到崩溃前的一致性状态。总之,数据库下次打开时会占用比正常关闭更长的时间。
- 注意:并不是所有异常关机后,下次启动时都可以恢复到正常状态,异常关机容易导致坏块的产生,这种情况下数据库是不能能正常启动的,如果处理不当,就会导致大量数据的丢失。
- rolling forward (前滚)
- Oracle启动实例并加载数据库,然后通过online redo logs 中的重做日志,重现实例崩溃前对数据库的操作。再恢复过程中对于已经提交的事务,但尚未写入数据文件的那部分数据全部写入数据文件。
- Oracle启动实例并加载数据库,然后通过online redo logs 中的重做日志,重现实例崩溃前对数据库的操作。再恢复过程中对于已经提交的事务,但尚未写入数据文件的那部分数据全部写入数据文件。
- Rolling Back (回滚)
- Rolling Forward 之后,虽然已经提交的修改操作更改的的数据都已经被写入数据文件,但是在实例崩溃时,部分未提交的事务操作的数据也被写入到数据文件,这些事务必须被撤销。
- Rolling Forward 之后,虽然已经提交的修改操作更改的的数据都已经被写入数据文件,但是在实例崩溃时,部分未提交的事务操作的数据也被写入到数据文件,这些事务必须被撤销。
- 触发LGWR进程的条件有:
- 1、用户提交。2、有1/3重做日志缓冲区未被写入磁盘。3、有大于1m的重做日志缓冲区未被写入磁盘。4、3秒超时。5、DBWR 需要写入的数据的 SCN 大于 LGWR 记录的 SCN,DBWR 触发LGWR 写入。
- 1、用户提交。2、有1/3重做日志缓冲区未被写入磁盘。3、有大于1m的重做日志缓冲区未被写入磁盘。4、3秒超时。5、DBWR 需要写入的数据的 SCN 大于 LGWR 记录的 SCN,DBWR 触发LGWR 写入。
- 数据库异常关机(比如突然断电,shutdown abort: 它会立即关闭数据库,等同于断电)之后,这时已经 commit 的事务已经记录到 online redo log 中,下次启动数据库时,Oracle 进行恢复操作,将 online redo log 中的事务操作调入内存中,进行相应操作后将数据记入到数据文件中,数据操作完成。
- 3、SCN(system change number)
- scn是当Oracle数据库更新后,由DBMS自动维护去累积递增的一个数字。当一个事物commit时,LGWR会将log buffer写入redo log file,同时也会将事物的SCN同步写入到 redo log file 内(wait-until-completed)。因此当你 commit transaction 时, 在成功的讯息返回之前,LGWR 必须先完整的完成上述行为之后,否则你是看不到提交成功的响应讯息。
- 可以理解的,返回的 SCN,也是目前 redo log file 最新的 SCN 纪录。 因为commit 后的交易才会有 SCN,而一旦 commit 就会立刻写入 redo log file 中。
- 系统时间标记与 scn 之间存在一张表,即 SYS 下的 SMON_SCN_TIME。

- 每 隔 5 分 钟 , 系 统 产 生 一 次 系 统 时 间 标 记 与 scn 的 匹 配 并 存 入SYS.SMON_SCN_TIME 表(由 SMON 进程来进行 Update 操作),该表中记录了最近 1440 个系统时间标记与 scn 的匹配记录,由于该表只维护了最近的 1440 条记录,即最近 5 天内的记录。
- 对 系统时间标记与 scn 的每 5 分钟匹配一次 做个说明,
- 比如:SCN:339988 对应 2011-01-25 17:00:00SCN:339989 对应 2011-01-25 17:05:00,当查询2011-01-25 17:00:00 到2011-01-25 17:04:59 这段时间点内的SCN时,oracle 都会将其匹配为 SCN:339988。
- 比如:SCN:339988 对应 2011-01-25 17:00:00SCN:339989 对应 2011-01-25 17:05:00,当查询2011-01-25 17:00:00 到2011-01-25 17:04:59 这段时间点内的SCN时,oracle 都会将其匹配为 SCN:339988。
- 查看 SCN 和 timestamp 之间的对应关系:
- select scn,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss') from sys.smon_scn_time order by 2;
- SQL>select dbms_flashback.get_system_change_number from dual;或者:SQL> select current_scn from v$database;CURRENT_SCN-----------1428603737
- timestamp 与 SCN 互换的 2 个方法:
- select timestamp_to_scn(to_date('2011-01-25 12:10:00','yyyy-mm-dd hh24:mi:ss')) from dual;
- select scn_to_timestamp(351277605) from dual;
- select timestamp_to_scn(to_date('2011-01-25 12:10:00','yyyy-mm-dd hh24:mi:ss')) from dual;
- Timestamp 与 SCN 之间映射关系的文章(ID 365536.1)How to map SCN with Timestamp before 10g [ID 365536.1]_David Dai -- Focus on Oracle-CSDN博客
- 实验操作:
- However, in earlier releases, while there is a system object -SYS.SMON_SCN_TIME that will provide the SCN to TIME mapping information. There is no conversion facility provided.
- SYS.SMON_SCN_TIME will have a maximum of 1440 rows and each record will be for a 5 minute period. Oracle maintains this information for maximum of 5 days after which the records will be recycled
- This means that data is stored 12 times per hour * 24 hours * 5 days=1440 rows.
- SCN value is stored internally as : i. SCN_wrap ii. SCN_base
- Whenever the SCN is incremented, the BASE component is incremented first unil it reaches it maximum. Once the BASE reaches the maximum value allowed, it is initialized to zero again after incrementing the WRAP by 1.----开始时 WRAP 为 0,即 SCN_WRP=0. 当 BASE 增长到最大值后,SCN_BAS变为 0. 同时 SCN_WRP 增长到 1
- Using this logic, we can calculate the timestamp of the SCN as follows:(SCN_WRP * 4294967296) + SCN_BAS should give us the SCN in the number format
- --SCN 的计算公式,这里我们看出 SCN 是根据 SCN_BAS 计算出来的。和系统时间是没有关系的。 只是方便我们来进行操作,如闪回恢复,而将 SCN 和 系统时间每隔 5 分钟进行一次映射。 映射完后,由 SMON 进程将映射关系写入SMON_SCN_TIME 表。 可以把 SCN 看成是 Oracle 内部的时间。
- To get the time/date for an SCN value in 9i, use the following example:
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-- (a) Get the current SCN base.
- SQL>select max(scn_bas) SCN_BASE from smon_scn_time;

- --(b) Get the complete SCN and the timestamp.SQL> alter session set NLS_DATE_FORMAT='DD-MON-YY HH:MI:SS';
- SQL> select time_dp TIMESTAMP, scn_wrp*4294967296+SCN_bas SCN from smon_scn_time where scn_bas='2044309'; 注意:11g 下 smon_scn_time 存储的记录可以超过 1440 条。

- However, in earlier releases, while there is a system object -SYS.SMON_SCN_TIME that will provide the SCN to TIME mapping information. There is no conversion facility provided.
- select scn,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss') from sys.smon_scn_time order by 2;
- scn是当Oracle数据库更新后,由DBMS自动维护去累积递增的一个数字。当一个事物commit时,LGWR会将log buffer写入redo log file,同时也会将事物的SCN同步写入到 redo log file 内(wait-until-completed)。因此当你 commit transaction 时, 在成功的讯息返回之前,LGWR 必须先完整的完成上述行为之后,否则你是看不到提交成功的响应讯息。
- 4、Checkpoint (检查点)
- 4.1检查点的定义:
- 大多数关系型数据库都采用"在提交时并不强迫针对数据块的修改完成"而是"提交时保证修改记录(以重做日志的形式)写入日志文件"的机制,来获得性能的优势。即:当用户提交事务,写数据文件是"异步"的,写日志文件是"同步"的。
- 这就可能导致数据库实例崩溃时,内存中的 DB_Buffer 中的修改过的数据,可能没有写入到数据块中。数据库在重新打开时,需要进行恢复,来恢复 DB Buffer 中的数据状态,并确保已经提交的数据被写入到数据块中。
- 检查点是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。
- 先看一下 checkpoint queue 概念,检查点发生后,触发 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 进程的检查点和心跳。
- 检查点发生以后,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 写数据文件,这样数据文件内容就不一致,若掉电需要进行崩溃恢复。
- oracle8 以后推出了 incremental checkpoint(增量检查点)的机制,在以前的版本里每 checkpoint 时都会做一个 full thread checkpoint(完全检查点),这样的话所有脏数据会被写到磁盘,巨大的 i/o 对系统性能带来很大影响。
- 为了解决这个问题,oracle 引入了 checkpoint queue 机制,每一个脏块会被移到检查点队列里面去,按照 low rdb(第一次对此块修改对应的 redo block address)来排列,靠近检查点队列尾端的数据块的 low rba 值是最小的,而且如果这些赃块被再次修改后它在检查点队列里的顺序也不会改变,这样就保证了越早修改的块越早写入磁盘。每隔 3 秒钟 ckpt 会去更新控制文件和数据文件,记录 checkpoint执行的情况。
- 触发 DBWR 进程的条件有:1. DBWR 超时,大约 3 秒 2. 系统中没有多余的空缓冲区来存放数据 3. CKPT 进程触发 DBWR
- checkpoint 有两个目的:1、确保数据一致性。2、使数据库能快速地恢复。
- Checkpoint 期间会有下面进程发生:
- 1. DBWR 写所有脏数据到数据文件;
- 2. LGWR 更新控制文件和数据文件的 SCN。
- 1. DBWR 写所有脏数据到数据文件;
- 大多数关系型数据库都采用"在提交时并不强迫针对数据块的修改完成"而是"提交时保证修改记录(以重做日志的形式)写入日志文件"的机制,来获得性能的优势。即:当用户提交事务,写数据文件是"异步"的,写日志文件是"同步"的。
- 4.2 Checkpoints 相关优化参数
- Checkpoints 是一个数据库优化的难点。频繁的 Checkpoints 可以实现快速的恢复,但也会使性能下降。怎样处理这个问题呢?
- 依赖于数据库数据文件的数量,一个 Checkpoint 可能是高速的运行。因为所有的数据文件在 Checkpoint 期间都会被冻结。更频繁的 Checkpoints 可以快速恢复数据库。这也客户对不按规定系统宕机的容忍的原因。然而,在一些特殊情况下,频繁的 Checkpoints 也不能保证可以快速恢复。我们假设数据库在 95%的时间内是正常运行,5%由于实例失败导致不可用,要求恢复。对大多数客户而言,他们更希望调整 95%的性能而不是 5%的宕机时间。这个假设表明,性能是摆在第一位的,所以我门的目标就是在优化期间减少 Checkpoints 的频繁度。
- 优化 Checkpoints 包括 4 个关键的初始化参数:
- - FAST_START_MTTR_TARGET
- - LOG_CHECKPOINT_INTERVAL
- - LOG_CHECKPOINT_TIMEOUT
- - LOG_CHECKPOINTS_TO_ALERT
- FAST_START_MTTR_TARGET:
- Oracle9i 以来 FAST_START_MTTR_TARGET 参数是调整 checkpoint 的首选的方法。FAST_START_MTTR_TARGET 可以指定单实例恢复需要的秒数。基于内部的统计,增长的 checkpoint 会自动调整的 checkpint 的目标以满足FAST_START_MTTR_TARGET 的需求。

- v$instance_recovery.estimated_mttr 显示当前估计需要恢复的秒数。这个值会被显示即使 FAST_START_MTTR_TARGET 没有被指定。
- v$instance_recovery.target_mttr 表明在短时间内 MTTR 的目标。
- v$mttr_target_advice 显示这个当前 MTTR 设置的工作量产生的 I/O 数量和其他 I/O。这个视图帮助用户评定这个在优化和恢复之前的平衡。
- Oracle9i 以来 FAST_START_MTTR_TARGET 参数是调整 checkpoint 的首选的方法。FAST_START_MTTR_TARGET 可以指定单实例恢复需要的秒数。基于内部的统计,增长的 checkpoint 会自动调整的 checkpint 的目标以满足FAST_START_MTTR_TARGET 的需求。
- LOG_CHECKPOINT_INTERVAL
- LOG_CHECKPOINT_INTERVAL 参数指定这个最大的重做块的间隔数目。如果 FAST_START_MTTR_TARGET 被指定,LOG_CHECKPOINT_INTERVAL不能被设置为 0。
- 在 大 多 数 Unix 系统的 OS 块 大 小 是 512 字 节 。 设 置LOG_CHECKPOINT_INTERVAL=10000 意味着这个增长的 checkpoint 不能追加到当前日志,因为多于 5M。如果你的重做日志是 20M,你将发出 4 个 checkpoint对每个重做日志。
- LOG_CHECKPOINT_INTERVAL 会发生影响当一个 checkpoint 发生时,小心设置这个参数,保持它随着重做日志文件大小变化而变化。checkpoint 频繁是这个影响数据库恢复的原因之一。短的 checkpoint 间隔意味数据库将快速恢复,也增加了资源的利用。这个参数也影响数据库向前回滚的时间。实际的恢复时间是基于这个时间,当然还有失败的类型和需要归档日志的数量。
- LOG_CHECKPOINT_INTERVAL 参数指定这个最大的重做块的间隔数目。如果 FAST_START_MTTR_TARGET 被指定,LOG_CHECKPOINT_INTERVAL不能被设置为 0。
- LOG_CHECKPOINT_TIMEOUT
- 这个参数指定 checkpoint 发出的时间间隔。换句话说,它指定一次脏数据多少时间写出一次。checkpoint 频率会影响这个数据库恢复的时间。长时间的间隔会要求数据库恢复要求更久。
- Oracle 建议用 LOG_CHECKPOINT_interval 去控制 checkpoint 而不用LOG_CHECKPOINT_TIMEOUT,LOG_CHECKPOINT_TIMEOUT 每 n 秒发一次checkpoint,不顾事务提交的频率。这可能会导致一些没有必要的 checkpoint 在事务已经变化的情况下。不必要的 checkpoint 必须被避免。
- 还有一个容易误解的地方:LOG_CHECKPOINT_TIMEOUT 会间隔性地发出 log switch。而 Log switch 会触发一个 checkpoint,但 checkpoint 不会导致一个log switch。唯一手工方式 alter system switch logfile 或者重新设置 redo logs 大小可以导致频繁 switch。
- SQL> alter system set log_checkpoint_timeout=300;[单位是秒]
- 这个参数指定 checkpoint 发出的时间间隔。换句话说,它指定一次脏数据多少时间写出一次。checkpoint 频率会影响这个数据库恢复的时间。长时间的间隔会要求数据库恢复要求更久。
- log_checkpoint_to_alert
- 设置为真,可以在告警日志中观察到增量检查点的触发。
- SQL> alter system set log_checkpoints_to_alert=true;
- 对于优化和恢复, 在线重做日志的大小是关键的。
- 设置为真,可以在告警日志中观察到增量检查点的触发。
- - FAST_START_MTTR_TARGET
- Checkpoint 触发条件
- 触发完全检查点 条件
- 发完全检查点,促使 DBWR 将检查点时刻前所有的脏数据写入数据文件。另外,一般正常运行期间的数据库不会产生完全检查点。
- 1. 通过正常事务处理或者立即选项关闭例程时(shutdown immediate 或者Shutdown normal).
- 2. 当通过设置初始化参数:
- LOG_CHECKPOINT_INTERVAL,
- LOG_CHECKPOINT_TIMEOUT ,
- FAST_START_IO_TARGET 强制时;
- LOG_CHECKPOINT_INTERVAL,
- 3. 当数据库管理员手动请求时:
- alter system checkpoint;
- alter tablespace ... offline;
- alter system checkpoint;
- 4. 每次日志切换时;
- alter system switch logfile
- alter system switch logfile
- 注意:1. alter system switch logfile 也将触发完全检查点的发生。2. alter database datafile ... offline 不会触发检查点进程。
- 如果是单纯的 offline datafile,那么将不会触发文件检查点,只有针对 offline tablespace 的时候才会触发文件检查点,这也是为什么 online datafile 需要 media recovery 而 online tablespace 不需要。
- 对于表空间的 offline 后再 online 这种情况,最好做个强制的 checkpoint 比较好。
- 发完全检查点,促使 DBWR 将检查点时刻前所有的脏数据写入数据文件。另外,一般正常运行期间的数据库不会产生完全检查点。
- 触发增量检查点
- 1. 在联机热备份数据文件前,要求该数据文件中被修改的块从DB_Buffer 写入数据文件中。所以,发出这样的命令:
- ALTER TABLESPACE tablespace_name BIGEN BACKUP / end backup; 也将触发和该表空间的数据文件有关的局部检查点;
- ALTER TABLESPACE tablespace_name BIGEN BACKUP / end backup; 也将触发和该表空间的数据文件有关的局部检查点;
- 2. 另外,ALTER TABLESPACE tablespace_name READ ONLY;ALTER TABLESPACE tablespace_name OFFLINE NORMAL;等命令都会触发增量检查点。
- 1. 在联机热备份数据文件前,要求该数据文件中被修改的块从DB_Buffer 写入数据文件中。所以,发出这样的命令:
- 检查点的一些困惑与思考???
- 1、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 成功的了,数据不会丢失!
- 对于 Oracle 来说,用户所做的 DML操作一旦被提交,则先是在 database buffer cache 中进行修改,同时在修改之前会将数据的前镜像保存在回滚段中,然后将修改之前和修改之后的数据都写入到 redo log buffer 中,当接收到 commit 命令之后,则 redo log buffer 开始写 redo log file ,并且记录此时的 scn,当 redo log file 写完了之后,表示这次事务提交操作已经确认被数据库记录了,只有当 redo log file 写成功了,才会给用户 Commit completed 的成功字样。
- 2、数据库发生一次 DBWn,是否将所有 buffer cache 中的 dirty buffer 都写入,还是先将脏队列中的数据写入?
- 这话看起来有道理,但实际上,dbwr 在写的时候又不断地在产生 dirty buffer ,所以说检查点发生的时候是期望把该时间点之前的所有脏缓冲区写入数据文件。所有的 buffer,不在 LRU list 上就在 dirty list 上, dbwr 写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。
- 这话看起来有道理,但实际上,dbwr 在写的时候又不断地在产生 dirty buffer ,所以说检查点发生的时候是期望把该时间点之前的所有脏缓冲区写入数据文件。所有的 buffer,不在 LRU list 上就在 dirty list 上, dbwr 写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。
- 1、Commit 成功后,数据还会丢失吗?
- 触发完全检查点 条件
- Checkpoints 是一个数据库优化的难点。频繁的 Checkpoints 可以实现快速的恢复,但也会使性能下降。怎样处理这个问题呢?
- 4.1检查点的定义:
最后修改时间:2022-04-14 08:33:11
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




