
我将为您深入解析Oracle数据库中确保数据一致性与可恢复性的核心机制——检查点(Checkpoint)。这是一个将内存中的修改与磁盘上的数据文件进行同步的关键过程。
第一部分:官方定义与核心作用
一、官方定义 (Official Definition)
检查点是一个数据库事件,其核心作用是通知数据库写进程(DBWn)将缓冲区缓存(Buffer Cache)中的脏缓冲区(Dirty Buffers)写入磁盘数据文件。此事件完成后,会更新数据文件头和控制文件中的SCN信息,以同步内存与磁盘的状态。
二、核心作用 (Purpose)
- 缩短实例恢复时间:这是最主要的作用。实例恢复需要应用从最后一次检查点位置开始的重做日志。检查点越频繁,需要应用的重做日志就越少,恢复时间就越短。
- 保证数据一致性:定期将内存中的修改持久化到磁盘,减少了因实例崩溃而丢失的数据量(最多丢失最后一次检查点之后的修改)。
- 协调数据库组件:确保数据文件、控制文件和重做日志在某个时间点处于一致的状态。
通俗比喻:
将Oracle数据库比作一个正在写作的作家。
- Buffer Cache:作家的桌面,上面放着正在修改的手稿。
- 重做日志(Redo Log):作家的日记,按时间顺序记录他写的每一句话。
- 数据文件(Data Files):最终成稿的书籍。
- 检查点(Checkpoint):作家定期将桌面上修改好的章节誊写到书籍中,并在日记上做个标记,写上“已誊写到第X页”。如果突然停电(实例崩溃),他只需要从日记上标记的位置开始,重新誊写最后一次之后的内容即可,而不需要从头开始。
第二部分:深入底层原理与管理机制
一、检查点队列 (Checkpoint Queue)
这是理解增量检查点的核心数据结构。
- 原理:Buffer Cache中的每一个脏数据块的缓冲区头(Buffer Header)都被链入一个双向链表,这个链表就是检查点队列。关键是,这个队列是按数据块第一次变脏时的SCN(Low RBA - Redo Block Address中的SCN部分)顺序排列的。
- 作用:它确保了在检查点发生时,DBWn会按照数据块被修改的顺序将它们写入磁盘。这对于恢复的一致性至关重要,因为它保证了重做日志的应用顺序与数据块的写入顺序是一致的。
二、检查点的类型 (Types of Checkpoints)
-
完全检查点 (Full Checkpoint):
- 触发条件:
ALTER SYSTEM CHECKPOINT、数据库正常关闭(SHUTDOWN NORMAL/IMMEDIATE)、表空间READ ONLY操作。 - 行为:要求DBWn将Buffer Cache中所有的脏块写入数据文件。这是一个代价相对较高的操作,在Oracle 8i之后,除非特定情况,通常由增量检查点取代。
- 触发条件:
-
增量检查点 (Incremental Checkpoint):
- 触发条件:这是Oracle 8i之后默认和主要的检查点机制。由
FAST_START_MTTR_TARGET参数、重做日志切换、或每隔3秒自动触发。 - 行为:不要求DBWn在一次事件中写完所有脏块。CKPT进程只是定期(约每3秒)将当前在检查点队列中最老的脏块对应的SCN(或RBA)——称为检查点位置——写入控制文件。DBWn则持续在后台写出检查点队列中的脏块,目标是让队列头部的SCN尽快追上控制文件中记录的检查点位置。
- 触发条件:这是Oracle 8i之后默认和主要的检查点机制。由
-
局部检查点 (Partial Checkpoint):
- 触发条件:表空间脱机(OFFLINE NORMAL)、表空间只读(READ ONLY)、表空间BEGIN BACKUP。
- 行为:仅强制写出与特定表空间相关的脏块。
-
线程检查点 (Thread Checkpoint):
- 触发条件:日志切换(ALTER SYSTEM SWITCH LOGFILE)。
- 行为:在日志切换时,数据库必须确保即将被覆盖的在线重做日志中的所有重做记录所对应的脏块都已被写入磁盘(除非使用ARCHIVELOG模式且日志已归档)。这触发了DBWn的写操作,并推进检查点位置。
三、核心进程:CKPT 和 DBWn
- DBWn (Database Writer):负责将脏块实际写入数据文件的工作进程。可以有多个(DBW0-DBW9, etc.)以并行化I/O操作。
- CKPT (Checkpoint Process):协调检查点过程的进程。它不负责写脏块,它的职责是:
- 在检查点发生时,更新控制文件和数据文件头中的SCN信息。
- 在增量检查点中,定期将检查点位置(RBA)写入控制文件。
- 在完全检查点时,通知DBWn开始工作,并等待其完成。
四、关键参数:FAST_START_MTTR_TARGET
- 作用:这是一个自我调优参数。你设置一个期望的实例恢复时间(秒),Oracle内部会自动计算一个目标RBA。DBWn会努力将检查点队列的头部(最早脏块)推进到这个目标RBA之前,以确保恢复时间能在你的期望之内。
- 机制:设置此参数后,Oracle会自动管理增量检查点的推进速度。值越小,DBWn写得越积极,I/O负载可能越高,但恢复时间越有保障。
第三部分:原理串联与示例
场景: 一个繁忙的数据库系统。
- 事务进行:多个事务修改数据,在Buffer Cache中创建了大量脏块。这些脏块按首次修改的SCN顺序被挂在检查点队列上。
- 增量检查点(每3秒):
- CKPT进程醒来,读取当前检查点队列头部的SCN(比如 SCN=1001)。
- 它将这个SCN(或对应的RBA)写入控制文件。这意味着Oracle向自己承诺:“所有SCN早于1001的更改都已持久化到磁盘,恢复时最多从SCN=1001开始。”
- DBWn持续工作:DBWn进程在后台持续工作,从检查点队列的头部开始,将一批批脏块写入数据文件。写入成功后,这些块从队列中移除。
- 日志切换触发检查点:
- 当前日志组写满了,发生日志切换。
- CKPT被触发。它检查下一个要覆盖的日志组中的最小RBA(比如对应SCN=1050)。
- 它通知DBWn必须将检查点队列中所有SCN早于1050的脏块全部写出。
- DBWn加速工作,直到队列头部SCN推进到1050。
- CKPT将新的检查点位置(SCN=1050)更新到控制文件和数据文件头。
- 现在,旧的日志组可以被重用了。
- 崩溃与恢复:
- 系统在SCN=1100时崩溃。
- 重启时,SMON进程读取控制文件中的检查点位置(SCN=1050)。
- 它发现数据文件头的SCN也是1050(因为检查点完成了)。
- 实例恢复开始:SMON从重做日志中找到SCN=1050的位置,开始前滚,重新应用所有SCN在1050到1100之间的重做记录。
- 前滚完成后,再回滚所有未提交的事务。
- 数据库被恢复到崩溃前的一致状态。
第四部分:争用、等待事件与排查解决
检查点机制的核心是协调DBWn写入和LGWR写入的速度。任何不匹配都会导致性能问题。
1. 检查点未完成 (Checkpoint Not Complete)
- 等待事件:
checkpoint not complete - 场景:日志切换时发生。
- 根本原因:DBWn写数据块的速度跟不上LGWR写日志的速度。LGWR需要切换到一个新的日志文件,但Oracle规定,在覆盖一个旧的日志文件之前,该日志文件所记录的所有更改必须已被DBWn写入数据文件(确保恢复可行性)。如果DBWn还没写完,LGWR就必须等待,从而产生这个事件。
- 影响:所有需要写重做日志的DML操作都会被挂起(因为LGWR在等待),数据库会出现短暂的“冻结”。
- 排查与解决:
- 增加重做日志组的大小和数量:更大的日志文件意味着日志切换频率降低,给DBWn更多的写入时间。
- 优化DBWn性能:
- 检查I/O子系统是否存在瓶颈(使用
iostat等工具)。 - 启用异步I/O(如果OS和存储支持)。
- 增加
DB_WRITER_PROCESSES参数(多CPU系统尤其有效)。
- 检查I/O子系统是否存在瓶颈(使用
- 检查
FAST_START_MTTR_TARGET:不要将其设置得过小,否则会迫使DBWn持续高负荷运行。
2. 空闲缓冲区等待 (Free Buffer Waits)
- 等待事件:
free buffer waits - 场景:服务器进程需要将新数据块读入Buffer Cache,但找不到空闲缓冲区。
- 根本原因:DBWn写出速度太慢,无法及时将脏块写入磁盘以腾出空间。而DBWn的写出受检查点进度影响。
- 解决方案:
- 同上,优化DBWn性能和I/O。
- 增大Buffer Cache(
DB_CACHE_SIZE)。
3. 写完成等待 (Write Complete Waits)
- 等待事件:
write complete waits - 场景:一个进程需要修改一个数据块,但这个数据块当前正被DBWn进程写入磁盘(即正在I/O过程中)。
- 原理:进程必须等待这个写操作完成才能继续修改,否则会破坏数据一致性。
- 解决方案:与
free buffer waits类似,核心是优化DBWn的写入性能。
第五部分:常用监控SQL
-
查看系统检查点信息:
SELECT * FROM V$INSTANCE_RECOVERY;- 重点关注:
TARGET_MTTR(目标恢复时间),ESTIMATED_MTTR(当前估算的恢复时间),WRITES_MTTR(为满足MTTR而需要的写操作),CKPT_BLOCK_WRITES(检查点触发的块写入数)。
- 重点关注:
-
监控恢复进度(在恢复期间使用):
SELECT * FROM V$RECOVERY_PROGRESS; -
查看数据文件头和控制文件的SCN信息:
SELECT FILE#, NAME, CHECKPOINT_CHANGE# FROM V$DATAFILE; -- 控制文件中记录的数据文件SCN SELECT FILE#, NAME, CHECKPOINT_CHANGE# FROM V$DATAFILE_HEADER; -- 数据文件头实际的SCN -- 如果两者不同,说明可能正在进行检查点或发生了介质恢复 -
监控检查点相关的统计信息:
SELECT NAME, VALUE FROM V$SYSSTAT WHERE NAME LIKE '%checkpoint%'; -
监控等待事件:
SELECT EVENT, TOTAL_WAITS, TIME_WAITED_MICRO, AVERAGE_WAIT_MICRO FROM V$SYSTEM_EVENT WHERE EVENT IN ('checkpoint not complete', 'free buffer waits', 'write complete waits') ORDER BY TIME_WAITED_MICRO DESC;
总结
官方总结:检查点是Oracle数据库实现数据一致性和快速恢复的核心机制。增量检查点通过持续更新控制文件中的检查点位置,并促使DBWn后台写出按修改顺序排列的脏块,极大地减少了恢复时间。其性能主要受限于DBWn的写入能力和I/O子系统的性能,常见的等待事件如checkpoint not complete是判断系统是否健康的关键指标。
通俗总结:检查点就是数据库的**“定期存档”** 行为。
- 目的:为了游戏(数据库)崩溃后,不用从头开始玩,而是从最近的存档点继续。
- 增量检查点:不是把整个游戏画面都存下来(完全检查点),而是每隔几秒就记一下“我已经安全地玩到了第X关”(更新控制文件)。存档的过程(DBWn写数据)则在后台慢慢进行。
- 问题:如果你玩游戏的进度(LGWR写日志)飞快,而存档速度(DBWn写数据)很慢,那么游戏就会强制你停下来等待存档(
checkpoint not complete),否则不敢让你继续,以免丢失进度。
DBA的职责就是确保“存档设备”(存储I/O)足够快,并合理配置“存档频率”(FAST_START_MTTR_TARGET、日志文件大小),让存档过程既安全又尽可能不影响游戏体验(数据库性能)。理解检查点,是掌握Oracle数据库恢复与性能调优的基石。
欢迎关注我的公众号《IT小Chen》
1124

被折叠的 条评论
为什么被折叠?



