一、相关概念:

CBC链:按照磁盘block地址链起来

LRU链:least,最近最少使用,按最少被使用干净的数据块连起来。LRU(冷)、MRU(热)

LRUW链:脏块按使用热度串起来,DBWR会周期性启动优先把脏数据(少被访问)写到磁盘,然后挂到LRU上。

检查点队列(CHECKPOINT QUEUE)链:按照块第一次脏的时间连接起来,即按照LRBA地址连接起来。


RBA:redo log的地址

每个脏块都存在:

LRBA:第一次被脏的redo log的地址

HRBA:最近一次被脏的redo log的地址

on disk rba:current地址组最后写入的一条日志地址。也可以理解为目前数据库所保存的最后一条日志。

SQL>select CPDRT,CPLRBA_SEQ||'.'||CPLRBA_BNO||'.'||CPLRBA_BOF "Low RBA",CPODR_SEQ||'.'||CPODR_BNO||'.'||CPODR_BOF "On disk RBA",CPODS,CPODT,CPHBT from x$kcccp;

162631352.jpg

说明:
CPDRT列是检查点队列中的脏块数目.
CPODS列是on disk rba的scn
CPODT列是on disk rba的时间戳
CPHBT列是心跳


CKPT进程:1、完全检查点   触发DBWR,将脏块写到磁盘。(例如关闭数据库时)

         2、增量检查点   将检查点队列的第一个块所对应的第一次脏的日志地址(LRBA)记录到控制文件中 (每隔3秒钟产生一次),但并不会去更新数据文件头,以及控制文件中数据库SCN以及文件条目SCN信息,当增量检查点发生时如果发现检查点队列太长结合系统I/O不太忙允许的情况下会触发DBWN将检查点队列按最早脏的块部分写入磁盘。


二、实例崩溃恢复原理:

163949732.jpg

在buffer cache中存在着脏块,当脏块来不及写到存盘上时,我们都知道内存中的数据断电后就不存在了,所以在断电或非正常关闭时会导致数据丢失。

丢失的数据又分为两类:1、未提交事务所修改的脏块(可以丢失,没必要恢复)

                     2、已提交事务的所对应的脏块(不能丢失,必须恢复),数据块提交了,不一定脏块就写到磁盘,但是日志必定已写到redo log(详细看lgwr、dbwn触发条件)


165614744.jpg

如上图,当修改的数据块提交了,其日志必然写入redo log,而log buffer断电后会丢失,但是log buffer里的记录的修改肯定是没提交的。


那么数据库实例崩溃后,那些是我们需要的日志呢?

首先确认终点,是磁盘中redo log current日志组中的最后一条日志(on disk rba),记录着数据库崩溃前最后一个有效的修改。而起点就是检查点队列对应的第一个块,最早脏的块第一次脏所对应的日志地址(lrba),因为lrba之前的日志所对应的块肯定已写到磁盘。


如果发生了实例崩溃,只需要在日志文件中找到检查点位置(low cache rba),从此处开始应用所有的重做日志文件,就完成了前滚操作,实例崩溃后,再次启动数据库,oracle会到控制文件中读取low cache rba,这就是检查点位置,从此处开始应用重做日志,应用到on disk rba的位置。on disk

rba是磁盘中重做日志文件的最后一条重做记录的rba.


在数据库实例崩溃恢复中有可能把不必要的脏块也恢复出来,因为lrba--on disk rba是连续的、按顺序的,中间有些日志可能是用户没有commit的,但是oracle对于未提交的数据块都会回滚(详细了解undo)。


oracle如何检测到需要进行数据库恢复?

详见SCN:http://bearbear.blog.51cto.com/4450702/1336601