RedoLog Checkpoint 和 SCN说明


一.Redolog作用

数据库异常关机(比如突然断电,shutdownabort:它会立即关闭数据库,等同于断电)之后,这时已经commit的事务已经记录到onlineredolog中,下次启动数据库时,Oracle进行恢复操作,将onlineredolog中的事务操作调入内存中,进行相应操作后将数据记入到数据文件中,数据操作完成。对于没有commit而已经写入数据文件或回退段的数据,也要进行回滚操作,将数据恢复到rollback的状态,使数据文件和控制文件恢复到崩溃前的一致性状态。总之,数据库下次打开时会占用比正常关闭更长的时间。

注意:并不是所有异常关机后,下次启动时都可以恢复到正常状态,异常关机容易导致坏块的产生,这种情况下数据库是不能正常启动的,如果处理不当,将会导致大量数据的丢失。具体参考我的blog:


RollingForward(前滚)
Oracle启动实例并加载数据库,然后通过OnlineRedologs中的重做日志,重现实例崩溃前对数据库的修改操作。在恢复过程中对于已经提交的事务,但尚未写入数据文件的那部分数据全部写入数据文件.


RollingBack(回滚)

RollingForward之后,虽然已经提交的修改操作更改的数据都已经被写入数据文件,但在实例崩溃时,部分未提交的事务操作的数据也被写入到数据文件,这些事务必须被撤销.

触发LGWR进程的条件有:
1.用户提交
2.有1/3重做日志缓冲区未被写入磁盘
3.有大于1M的重做日志缓冲区未被写入磁盘
4.3秒超时
5.DBWR需要写入的数据的SCN大于LGWR记录的SCN,DBWR触发LGWR写入。

二.Checkpint(检查点)

2.1检查点定义
大多数关系型数据库都采用"在提交时并不强迫针对数据块的修改完成"而是"提交时保证修改记录(以重做日志的形式)写入日志文件"的机制,来获得性能的优势。

这句话的另外一种描述是:

当用户提交事务,写数据文件是"异步"的,写日志文件是"同步"的。

这就可能导致数据库实例崩溃时,内存中的DB_Buffer中的修改过的数据,可能没有写入到数据块中。数据库在重新打开时,需要进行恢复,来恢复DBBuffer中的数据状态,并确保已经提交的数据被写入到数据块中。检查点是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。


要了解这个检查点,首先要知道checkpointqueue概念,检查点发生后,触发DBWn,CKPT获取发生检查点时对应的SCN,通知DBWn要写到这个SCN为止,DBWR写dirtybuffer是根据buffer在被首次modify的时候的时间的顺序写出,也就是buffer被modify的时候会进入一个queue(checkpointqueue),DBWr就根据queue从其中批量地写到数据文件。由于这里有一个顺序的关系,所以dbwr的写的进度就是可衡量的,写到哪个buffer的时候该buffer的首次变化时候的scn就是当前所有数据文件block的最新scn,但是由于无法适时的将dbwr的进度记录下来,所以oracle选择了一些策略。其中就包括ckpt进程的检查点和心跳。


检查点发生以后,CKPT进程检查checkpointqueue(也就是脏块链表)是否过长,如果是,则触发DBWn,将一部分脏块写入数据文件,从而缩短checkpointqueue。

checkpoint发生时,一方面通知dbwr进行下一批写操作,(dbwr写入的时候,一次写的块数是有一个批量写的隐藏参数控制的);另一方面,oracle采用了一个心跳的概念,以3秒的频率将dbwr写的进度反应到控制文件中,也就是把dbwr当前刚写完的dirtybuffer对应的scn写入数据文件头和控制文件,这就是检查点scn。

这个3秒和增量检查点不是一个概念,3秒只是在控制文件中,ckpt进程去更新当前dbwr写到哪里了,这个对于ckpt进程来说叫heartbeat,heartbeat是3秒一次,3秒可以看作不停的检查并记录检查点执行情况(DBWR的写进度)。


检查点发生之后数据库的数据文件、控制文件处于一致状态的含义是不需要进行介质恢复,只表示数据文件头一致,但是并不表示数据文件内容一致,因为数据文件内容可能在没有发生检查点的其它情况下的dbwr写数据文件,这样数据文件内容就不一致,若掉电需要进行崩溃恢复。

触发DBWR进程的条件有:
1.DBWR超时,大约3秒
2.系统中没有多余的空缓冲区来存放数据
3.CKPT进程触发DBWR

2.2Checkpoint触发条件


oracle8以后推出了incrementalcheckpoint(增量检查点)的机制,在以前的版本里每checkpoint时都会做一个fullthreadcheckpoint(完全检查点),这样的话所有脏数据会被写到磁盘,巨大的i/o对系统性能带来很大影响。为了解决这个问题,oracle引入了checkpointqueue机制,每一个脏块会被移到检查点队列里面去,按照lowrdb(第一次对此块修改对应的redoblockaddress)来排列,靠近检查点队列尾端的数据块的lowrba值是最小的,而且如果这些赃块被再次修改后它在检查点队列里的顺序也不会改变,这样就保证了越早修改的块越早写入磁盘。每隔3秒钟ckpt会去更新控制文件和数据文件,记录checkpoint执行的情况。

触发CheckPoint(检查点)条件有很多,比如:

1.通过正常事务处理或者立即选项关闭例程时(shutdownimmediate或者Shutdownnormal),

2.当通过设置初始化参数:

LOG_CHECKPOINT_INTERVAL,

LOG_CHECKPOINT_TIMEOUT,

FAST_START_IO_TARGET强制时;
3.当数据库管理员手动请求时:

ALtersystemcheckpoint;
altertablespace...offline;


4.每次日志切换时;

altersystemswitchlogfile


注意:

1.altersystemswitchlogfile也将触发完全检查点的发生。
2.alterdatabasedatafile...offline不会触发检查点进程。

如果是单纯的offlinedatafile,那么将不会触发文件检查点,只有针对offlinetablespace的时候才会触发文件检查点,这也是为什么onlinedatafile需要mediarecovery而onlinetablespace不需要。

对于表空间的offline后再online这种情况,最好做个强制的checkpoint比较好。

关于offlinedatafile和tablespace的区别也可以参考我的blog:

ALTERDATABASE与ALTERTABLESPACEOFFLINE的区别

http://blog.youkuaiyun.com/tianlesoftware/archive/2009/11/30/4898800.aspx

以上的触发条件将触发完全检查点,促使DBWR将检查点时刻前所有的脏数据写入数据文件。另外,一般正常运行期间的数据库不会产生完全检查点。

下面很多事件将导致增量检查点,比如:

1.在联机热备份数据文件前,要求该数据文件中被修改的块从DB_Buffer写入数据文件中。所以,发出这样的命令:
ALTERTABLESPACEtablespace_nameBIGENBACKUP&endbackup;也将触发和该表空间的数据文件有关的局部检查点;

2.另外,
ALTERTABLESPACEtablespace_nameREADONLY;
ALTERTABLESPACEtablespace_nameOFFLINENORMAL;
等命令都会触发增量检查点。

2.3关于检查点的一点具体应用讨论


2.3.1.Commit成功后,数据还会丢失吗?


对于Oracle来说,用户所做的DML操作一旦被提交,则先是在databasebuffercache中进行修改,同时在修改之前会将数据的前镜像保存在回滚段中,然后将修改之前和修改之后的数据都写入到redologbuffer中,当接收到commit命令之后,则redologbuffer开始写redologfile,并且记录此时的scn,当redologfile写完了之后,表示这次事务提交操作已经确认被数据库记录了,只有当redologfile写成功了,才会给用户Commitcompleted的成功字样。而对于Databasebuffercache中的dirtybuffer则会等待触发DBWn才写入,但是如果此时断电,则数据已经被记录到了redologfile中,系统在重新启动的时候,会自动进行嵌滚和回滚来保证数据的一致。所以,只要是commit成功的了,数据不会丢失!

2.3.2.数据库发生一次DBWn,是否将所有buffercache中的dirtybuffer都写入,还是先将脏队列中的数据写入?

这话看起来有道理,但实际上,dbwr在写的时候又不断地在产生dirtybuffer,所以说检查点发生的时候是期望把该时间点之前的所有脏缓冲区写入数据文件。
所有的buffer,不在LRUlist上就在dirtylist上,dbwr写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。
所以说要是dbwr将dirtylist也好,lrulist上的也好,要实现全部写入,都是一个现实系统中很难存在的现象。dirty总是在不断的产生,dbwr总是在不断地写,增量检查点发生的时候也并不意味着一定要更新数据文件头,检查点开始的时候只表示该次检查点结束的时候要更新数据文件头的话数据文件头具有该时间点的一致性。


2.3.3.关于检查点等待事件:


有些事件的产生必须等待检查点的完成,才能开始数据库的其它操作:日志文件切换就是其中一个事件,日志切换必须等待检查点完成。


logfileswitch(checkpointincomplete)这个等待事件本身也说明,日志切换时产生的检查点是需要等待的,这个日志文件所对应脏块全部写完后,检查点进程更新控制文件和数据头,然后这个检查点才能算完成。
也就是说日志切换必须等待检查点完成,而检查点在等待DBWn完成。


这种等待DBWn完成的检查点,最后一步写入控制文件和数据文件头的SCN,肯定是DBWn完成的最后一块的SCN。


2.3.4.检查点为什么要等待dbwr完成后才进行切换(logswitch)?


logswitch时,是不能立即switch到active状态的,loggroup必须等待。

active表示该loggroup还没有完成归档(归档模式下)或者该loggroup有进行instancerecovery的需要用到的日志。所以当checkpoint发生时,如果dbwr还没有写完它该写完的dirtybuffers(该checkpoint时间点以前产生的dirtybuffers,靠scn判断),则该loggroup处于active状态,不会进行日志切换,当然也不会发生日志文件被覆盖的问题了。


2.3.5.如果没有设置archivelog,在检查点发生后,发生logswitch一个轮回,logfile是否会被覆盖掉?


当检查点发生后,会触发lgwr,lgwr会把此时SCN以前在redobuffer中的所有操作写到redologfile,同时lgwr也会触发dbwr进程,dbwr也开始把此刻以前databasebuffer中的dirtybuffer队列中的操作写入datafile。
其实检查点发生后,就是lgwr和dbwr写buffer到磁盘文件的过程,但是两者的读写速度时不同的,dbwr写buffer到数据文件的过程相对较慢,因为dbwr写过程是一个随机读取存储的过程。Lgwr写buffer到redo文件的过程比dbwr要快很多,因为lgwr是顺序读取写入的。


由于以上lgwr和dbwr写操作的速度不同,就产生了一个等待问题。即当lgwr
轮循一圈后,要进行日志切换,覆盖redologfile,但是此时dbwr还没有写完,那么lgwr就会出现等待,oracle也会hang在那里,同时alter文件中会提示一个相应的提示checkpointnotcomplete。等检查点完成后数据库自动恢复正常。
当logswitch时,会触发检查点,标记检查点时,DBWR要把logfile中coveredbythelogbeingcheckpointed的数据写入到数据文件上,如果Dbwr没有写完,那么前一个logfile是不能被覆盖的。因此必须等检查点完毕,也可以说是将要被覆盖的日志相关的数据块全部写入数据文件后,该日志文件才能被覆盖!


如果这种情况出现,alert文件中会记录checkpointnotcomplete事件,这通常表明你的dbwr写入过慢或者logfile组数过少或logfile太小。


2.3.6.检查点发生时,出现日志切换,但是dbwr还没有写完,是否会覆盖redologfile,如果此时掉电,dbwr挂起,会出现丢失数据吗?

不会覆盖redo文件,要等待dbwr写完才覆盖。或者说要等待检查点完成才覆盖。
如果DBWn正在写的脏块是指对应到即将被覆盖的那个日志文件的,那么,因为在这些操作完成之前,不可能有覆盖这件事发生,假设你预料的掉电发生了,不会有什么问题,实例恢复时的前滚从刚才准备覆盖的那个日志文件开始。

如果正在写的脏块是指对应到刚刚被写满的那个日志文件的,肯定一时半会也写不完,日志切换也不会等它,如果切换成功后dbwr挂了,后面的写脏块操作估计也还没完成,但是,刚写满的那个文件并没有被覆盖,也不会有任何问题。
因此不会出现数据丢失!


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

2.3.7.altersystenswitchlogfile会触发完全检查点;但是为什么,日志切换以后检查点只能记录到上一次归档日志产生的时间呢?而不是现在归档日志产生的时间呢?


因为这时的checkpointenqueue队列中,也就是脏块队列中脏块还不够多,还不足以触发DBWn写脏块。所以,内存里需要写入的脏块所对应的redo还存在于上一个redolog里,这时你去看该redolog的status为active。

我们可以通过一下语句查看相关信息:
SQL>select*fromx$kccrt;

三.SCN(systemchangenumber)

3.1SCN定义:

SCN是当Oracle数据更新后,由DBMS自动维护去累积递增的一个数字。当一个事务commit时,LGWR会将logbuffer写入redologfile,同时也会将该事务的SCN同步写入到redologfile内(wait-until-completed)。因此当你committransaction时,在成功的讯息返回之前,LGWR必须先完整的完成上述行为之后,否则你是看不到提交成功的响应讯息。


我们可以查询目前系统最新的SCN
selectdbms_flashback.get_system_change_numberfromdual;


可以理解的,这里返回的SCN,也是目前redologfile最新的SCN纪录。因为commit后的交易才会有SCN,而一旦commit就会立刻写入redologfile中。

3.2CHECKPOINT和SCN的关连

checkpoint发生的目的就是要把储存在buffer内的已提交的事务写回disk,否则一旦发生crash,需要进行recovery时,你就必须花很多的时间从redologfile内最后的SCN交易开始进行recovery,这样在商业应用上是很浪费时间和没有效率的。


重点在于当commit一个事务时,只会立刻将redobuffer写入redologfile内,但是并不会马上将该update后的block(dirtyblock)同步写回diskdatafile中,这是为了减少过多diskIO的考虑,所以采取batch的方式写入。


Whenacheckpointoccurs,Oraclemustupdatetheheadersofalldatafilestorecordthedetailsofthecheckpoint.ThisisdonebytheCKPTprocess.TheCKPTprocessdoesnotwriteblockstodisk;DBWnalwaysperformsthatwork.


在shutdownnormalorshutdownimmediate下,也就是所谓的cleanshutdown,checkpoint也会自动触发,并且把SCN纪录写回。

当发生checkpoint时,会把SCN写到四个地方去。

三个地方于controlfile内,一个在datafileheader。


Controlfile三个地方为


1.SystemcheckpointSCN===========>(SYSTEMCHECKPOINTSCNincontrolfile)
SQL>selectcheckpoint_change#fromv$database;
CHECKPOINT_CHANGE#
--------------------
292767
2.DatafilecheckpointSCN===============>(DATAFILECHECKPOINTSCNincontrolfile)
SQL>selectname,checkpoint_change#
fromv$datafilewherenamelike'%users01%';
NAMECHECKPOINT_CHANGE#
-------------------------------------------------------
/u02/oradata/OMFD1/users01.dbf292767
3.StopSCN======================>(STOPSCNincontrolfile)
SQL>selectname,last_change#
fromv$datafilewherenamelike'%users01%';
NAMELAST_CHANGE#
-----------------------------------------------
/u02/oradata/OMFD1/users01.dbf


正常datafile在read-writemode下last_change#一定是NULL


另外一个地方在datafileheader内


4.StartSCN================================>(DATAFILEHEADER)
SQL>selectname,checkpoint_change#
fromv$datafile_headerwherenamelike'%users01%';
NAMECHECKPOINT_CHANGE#
-------------------------------------------------------
/u02/oradata/OMFD1/users01.dbf292767

3.3相关问题


3.3.1为什么储存在CONTROLFILE中要分为两个地方(SYSTEMCHECKPOINTSCN,DATAFILECHECKPOINTSCN)?

当你把一个tbs设为read-only时,他的SCN会冻结停止,此时DATAFILECHECKPOINTSCN是不会再递增改变的,但是整体的SYSTEMCHECKPOINTSCN却仍然会不断递增前进。
所以,这就是为什么需要分别在两个地方储存SCN。

3.3.2正常shutdowndatabase后,SCN会发生什么变化?
我们可以把数据库开在mountmode
selectcheckpoint_change#fromv$database;
CHECKPOINT_CHANGE#
--------------------
293184
selectname,checkpoint_change#,last_change#fromv$datafilewherenamelike'%user%';
NAMECHECKPOINT_CHANGE#LAST_CHANGE#
---------------------------------------------------------------------
/u02/oradata/OMFD1/users01.dbf293184293184
可以看到储存在controlfile中的三个SCN位置都是相同,注意此时的stopscn不会是NULL,而是等于startscn


我们来查询datafileheaderSCN:
selectname,checkpoint_change#fromv$datafile_headerwherenamelike'%users01%';
NAMECHECKPOINT_CHANGE#
-------------------------------------------------------
/u02/oradata/OMFD1/users01.dbf293184


当cleanshutdown时,checkpoint会进行,并且此时datafile的stopscn和startscn会相同。等到我门开启数据库时,Oracle检查datafileheader中的startscn和存于controlfile中的datafile的scn是否相同,如果相同,接着检查startscn和stopscn是否相同,如果仍然相同,数据库就会正常开启,否则就需要recovery...等到数据库开启后,储存在controlfile中的stopscn就会恢复为NULL值,此时表示datafile是open在正常模式下了。


如果不正常SHUTDOWN(shutdownabort),则mount数据库后,你会发现stopscn并不是等于其它位置的scn,而是等于NULL,这表示Oracle在shutdown时没有进行checkpoint,下次开机必须进行crashrecovery。


crashrecovery
必须先进行rollforward(从redologfile中从目前的startSCN开始,重做后面的已提交之交易)。再从rollbacksegment做rollback未完成(deadtransaction)交易。检验controlfile中的SCN会等于datafileheader的SCN


select'controlfile'"SCNlocation",name,checkpoint_change#
fromv$datafilewherenamelike'%users01%'
union
select'fileheader',name,checkpoint_change#
fromv$datafile_headerwherenamelike'%users01%';
SCNlocationNAMECHECKPOINT_CHANGE#
---------------------------------------------------------------------
controlfile/u02/oradata/OMFD1/users01.dbf293188
fileheader/u02/oradata/OMFD1/users01.dbf293188


3.3.3crashrecovery和mediarecovery的比较


启动数据库时,如果发现STOPSCN=NULL,表示需要进行crashrecovery;启动数据库时,如果发现有datafileheader的STARTSCN不等于储存于CONTROLFILE的DATAFILESCN,表示需要进行Mediarecovery


STOPSCNequalNULL==>NEEDCRASHRECOVERY
DATAFILEHEADERSTARTSCNnotequalCONTROLFILESCN==>NEEDMEDIARECOVERY


3.3.4RECOVERYDATABASE两种常见问题
1)RECOVERDATABASEUNTILCANCEL==>OPENDATABASERESETLOG
==>DATAFILEHEADERSCN一定会小于CONTROLFILE的DATAFILESCN


如果你有进行RESTOREDATAFILE,则该RESTORE的DATAFILEHEADERSCN一定会小于目前CONTROLFILE的DATAFILESCN,此时会无法开启数据库,必须进行mediarecovery。重做archivelog直到该datafileheader的SCN=currentscn


restoredatafile后,可以mountdatabase然后去检查controlfileanddatafileheader的SCN


select'controlfile'"SCNlocation",name,checkpoint_change#
fromv$datafilewherenamelike'%users01%'
union
select'fileheader',name,checkpoint_change#
fromv$datafile_headerwherenamelike'%users01%';


SCNlocationNAMECHECKPOINT_CHANGE#
---------------------------------------------------------------------
controlfile/u02/oradata/OMFD1/users01.dbf313551
fileheader/u02/oradata/OMFD1/users01.dbf313401


2)RECOVERDATABASEUNTILCANCELUSINGBACKUPCONTROLFILE;===>OPENDATABASERESETLOG


==>DATAFILEHEADERSCN一定会大于CONTROLFILE的DATAFILESCN


如果只是某TABLE被DROP掉,没有破坏数据库整体数据结构,还可以用NCOMPLETERECOVERY解决如果是某个TABLESPACEORDATAFILE被DROP掉,因为档案结构已经破坏,目前的CONTROLFILE内已经没有该DATAFILE的信息,就算你只RESTOREDATAFILE然后进行INCOMPLETERECOVERY也无法救回被DROP的DATAFILE。


只好RESOTRE之前备份的CONTROLFILE(里头被DROPDATAFILEMetadata此时还存在),不过RESTORECCONTROLFILE后此时Oracle会发现CONTROLFILE内的SYSTEMSCN会小于目前的DATAFILEHEADERSCN,也不等于目前储存于LOGFILE内的SCN,此时就必须使用RECOVERDATABASEUNTILCANCELUSINGBACKUPCONTROLFILE到DROPDATAFILEORDROPTABLESPACE之前的SCN。

另一种特殊状况就是,万一不幸地所有CONTROLFILE都遗失了,也必须用这种方式救回,所以请做MULTIPLEXING。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值