一、检查点概念
1、检查点的概念
大多数关系型数据库都采用"在提交时并不强迫针对数据块的修改完成"而是"提交时保证修改记录(以重做日志的形式)写入日志文件"的机制,来获得性能的优势。
这句话的另外一种描述是:当用户提交事务,写数据文件是"异步"的,写日志文件是"同步"的。
这就可能导致数据库实例崩溃时,内存中的DB_Buffer 中的修改过的数据,可能没有写入到数据块中。
数据库在重新打开时,需要进行恢复,来恢复DB Buffer 中的数据状态,并确保已经提交的数据被写入到数据块中。
检查点是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。
【接下一节】
2、关于检查点队列的概念
要了解这个检查点,首先要知道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进程的检查点和心跳。
【接下一节】
3、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的写进度)。
注意:此处的3秒检查点,并不会触发dbwr写,而只是记录DBWr的进度(也就是把dbwr当前刚写完的dirty buffer对应的scn 写入数据文件头和控制文件);这是三秒触发的检查点与其它条件触发检查点不同的地方。
检查点发生之后数据库的数据文件、控制文件处于一致状态的含义是:不需要进行介质恢复,只表示数据文件头一致,但是并不表示数据文件内容一致,因为数据文件内容可能在没有发生检查点的其他情况下(查看dbwr的其他触发条件,dbwr并不是只有当检查点发生的时候才写,它大约有十几种种条件触发写操作)的dbwr写数据文件,这样数据文件内容就不一致,若掉电需要进行崩溃恢复。
【接下一节】
4、检查点的目的
oracle的目的就是缩短崩溃恢复时间!
oracle如何缩短恢复时间?
1:检查点机制
2:心跳机制
二、检查点的分类
检查点分为:完全检查点(full checkpoint)和增量检查点
1、完全检查点
(1)完全检查点作用:
记下当前的scn号, 将此scn号之前所有的脏块一次性写完,再将该scn号同步更新控制文件和数据文件头。
(2)触发完全检查点条件:
--正常关闭数据库:shutdown immediate --手动检查点切换:alter system checkpoint --日志切换:alter system switch logfile --数据库热备模式:alter database begin backup --当通过设置初始化参数LOG_CHECKPOINT_INTERVAL、LOG_CHECKPOINT_TIMEOUT和FAST_START_IO_TARGET强制时; 上面几种情况,将触发完全检查点,促使DBWR将检查点时刻前所有的脏数据写入数据文件。
2、增量检查点
(1)增量检查点的作用
--在内存中被修改过的块,在oracle中都被统称为脏块.脏块按照首次变脏的时间顺序被一个双向链表指针串联起来,这称做检查点队列。
--当增量检查点发生时,DBWR就会被触发,沿着检查点队列的顺序将部分脏块刷新到磁盘上,每次刷新截止的那个块的位置就叫检查点位置,检查点位置之前的块,都是已经刷新到磁盘上的块。而检查点位置对应的日志地址(RBA)又总是被记录在控制文件中。如果发生系统崩溃,这个最后的检查点位置就是实例恢复运用日志的起点。
--增量检查点使检查点位置前移。进而缩短实例恢复需要的日志起点和终点之间的距离,触发增量检查点越频繁,实例恢复的时间越短,但数据库性能受到频繁IO影响会降低。
--增量检查点不会同步更新数据文件头的SCN。
--增量检查点并不是将脏列表中的所有脏块都写出到数据文件中,而是写出一部分,保证满足所有条件即可。
(2)增量检查点的触发条件
--90% OF THE SMALLEST REDO LOGFILE:最后一次增量检查点与当前日志文件末尾所差的redo block数量如果超过最小redo log的90%,那么就会触发增量检查点。 --FAST_START_MTTR_TARGET: 实例恢复的时间限制,oracle将这个时间换算成redo blocks数量,当log buffer中未写入log file的redo block数量超过这个值,就会触发增量检查点--FAST_START_IO_TARGET:实例恢复所需要读取的redo blocks数量,当log buffer中未写入log file的redo block数量超过这个值,就会触发增量检查点。 --LOG_CHECKPOINT_TIMEOUT: 两次增量检查点的时间间隔 --LOG_CHECKPOINT_INTERVAL:最后一次增量检查点与当前日志文件末尾所差的redo block数量 --在联机热备份数据文件前,要求该数据文件中被修改的块从DB_Buffer写入数据文件中。所以,发出这样的命令: ALTER TABLESPACE tablespace_name BIGEN BACKUP & end backup;也将触发和该表空间的数据文件有关的局部检查点; --另外,下述命令都会触发增量检查点。 ALTER TABLESPACE tablespace_name READ ONLY; ALTER TABLESPACE tablespace_name OFFLINE NORMAL;
3、关于检查点需要注意的:
(1)注意事项1:完全检查点容易出现的误区
alter system switch logfile: 也将触发完全检查点的发生。 alter database datafile ... offline:不会触发检查点进程。
如果是单纯的offline datafile,那么将不会触发文件检查点,只有针对offline tablespace的时候才会触发文件检查点,这也是为什么online datafile需要media recovery,而online tablespace不需要。
(2)注意事项2:
对于表空间的offline后再online这种情况,最好做个强制的checkpoint比较好。
上面几种情况,将触发完全检查点,促使DBWR将检查点时刻前所有的脏数据写入数据文件。
另外,一般正常运行期间的数据库不会产生完全检查点,而是产生增量检查点。
(3)注意事项3:
每隔三秒也会触发检查点,但是并没有被oracle正式作为一种检查点的触发方式列入文档,并且这个3秒是记录dbwr进度而不是通知dbwr写。
这是三秒触发的检查点与其它条件触发检查点不同的地方。
三、关于SCN的功能分类
SCN(System Chang Number)作为oracle中的一个重要机制,在数据恢复、Data Guard、Streams复制、RAC节点间的同步等各个功能中起着重要作用。根据功能可以分为如下几类:
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值
(1)打开并运行时
数据库打开并运行之后,控制文件中的系统检查点、控制文件中的数据文件检查点scn和每个数据文件头中的启动scn都是相同的。控制文件中的每个数据文件的终止scn都为null.
(2)安全关闭时
在安全关闭数据库的过程中,系统会执行一个检查点动作,这时所有数据文件的终止scn都会设置成数据文件头中的那个启动scn的值。
(3)重新启动时
在数据库重新启动的时候,Oracle将文件头中的那个启动scn与数据库文件检查点scn进行比较,是否匹配。
如果这两个值相互匹配,Oracle接下来还要比较数据文件头中的启动 scn和控制文件中数据文件的终止scn。
如果这两个值也一致,就意味着所有数据块都已经提交,所有对数据库的修改都没有在关闭数据库的过程中丢失,因此这次启动数据库的过程也不需要任何恢复操作,此时数据库就可以打开了。
当所有的数据库都打开之后,存储在控制文件中的数据文件终止scn的值再次被更改为 null,这表示数据文件已经打开并能够正常使用了。
四、事务过程
我们再看下Oracle事务中的数据变化是如何写入数据文件的:
1、 事务过程
--事务开始 --在buffer cache中找到需要的数据块,如果没有找到,则从数据文件中载入buffer cache中; -- 事务修改buffer cache的数据块,该数据被标识为“脏数据”,并被写入log buffer中; --事务提交,LGWR进程将log buffer中的“脏数据”写入redo log file中; --当发生checkpoint,CKPT进程更新所有数据文件的文件头中的信息,DBWr进程则负责将Buffer Cache中的脏数据写入到数据文件中。
经过上述5个步骤,事务中的数据变化最终被写入到数据文件中。
2、意外发生
但,一旦在上述中间环节时,数据库意外宕机了,在重新启动时如何知道哪些数据已经写入数据文件、哪些没有写呢(同样,在DG、streams中也存在类似疑问:redo log中哪些是上一次同步已经复制过的数据、哪些没有?)
3、SCN的作用
SCN机制就能比较完善的解决上述问题。
SCN是一个数字,确切的说是一个只会增加、不会减少的数字。正是它这种只会增加的特性确保了Oracle知道哪些应该被恢复、哪些应该被复制。
(1)总共有4种SCN:
系统检查点(System Checkpoint)SCN 数据文件检查点(Datafile Checkpoint)SCN 结束SCN(Stop SCN) 开始SCN(Start SCN)
其中前面3种SCN存在于控制文件中,最后一种则存在于数据文件的文件头中。
(2)存在于控制文件中的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都不会被更新。
五、关于low cache rba与on disk rba的理解:
1、简单理解DBWR和LGWR的写进度
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进程更新控制文件的进度是不同的
六、关于检查点的一点具体应用讨论:
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成功的了(严谨一点说,redo log和undo也正常的情况下),数据不会丢失!
2、数据库发生一次DBWn,是否将所有buffer cache中的dirty buffer都写入,还是先将脏队列中的数据写入?
这话看起来有道理,但实际上,dbwr在写的时候又不断地在产生dirty buffer ,所以说检查点发生的时候是期望把该时间点之前的所有脏缓冲区写入数据文件。
所有的buffer,不在LRU list上就在dirty list上, dbwr写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。
所以说要是dbwr将dirty list也好,lru list上的也好,要实现全部写入,都是一个现实系统中很难存在的现象。
dirty总是在不断的产生,dbwr总是在不断地写,增量检查点发生的时候也并不意味着一定要更新数据文件头,检查点开始的时候只表示该次检查点结束的时候要更新数据文件头的话数据文件头具有该时间点的一致性。
3、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
该两参数信息请查阅http://tahiti.oracle.com
而ITL中的commit SCN则跟consistent gets and delay block cleanout有关
数据文件头的SCN是检查点发生时更新的,代表着当恢复的时候从这个SCN点开始在log file中寻找redo开始做恢复。
4、怎么解释这个现象?看下面的操作!
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)
-----------------------------------
©著作权归作者所有:来自51CTO博客作者Oracle小混子的原创作品,请联系作者获取转载授权,否则将追究法律责任
oracle技术之检查点及SCN深入研究
https://blog.51cto.com/19880614/1194643