我们知道当每个事务提交时,ORACLE会把REDO BUFFER(以下称RB)写到REDO LOG FILE(以下称RLF,也表示REDO LOG FILE GROP)里,同时在RLF里生成一条COMMIT记录,格式如下:
Redo log entry
省略……………….
Redo log entry
Commit a;
Redo log entry
Commit b;
省略……………….
Redo log entry
Redo log entry
Commit c;
Redo log entry
COMMIT 记录表示提交,我们知道ORACLE在COMMIT时并不通知DBWR写脏数据到磁盘上.这种设计会带来几个问题:
1,当实例进行崩溃时,并不知道哪些数据已经写到磁盘上了.有些人可能会说扫描整个RLF,当RLF文件比较大的时候,这可能需要一个相当长的时间;
2,当实例进行崩溃时,扫描哪个RLF的问题,如果RLF的个数很多,那么是不是需要全部扫描?如果是,那么整个实例恢复的时间变得相当漫长了.
通过引入一种叫作CHECKPOINT机制后,会在REDO中增加CHECKPOINT记录.格式如下:
Redo log entry
省略……………….
Redo log entry
Commit a;
Redo log entry
Commit b;
CHECKPOINT I;
省略……………….
Redo log entry
Redo log entry
Commit c;
CHECKPOINT j ;
Redo log entry;
当生成一个条CHECKPOINT记录时,会通知DBWR把脏数据(CHECKPOINT Q)写到数据文件中.这样就保证了在CHECKPOINT记录之前的事务修改的块全部都写到数据文件中.在上图中可以看出在CHECKPOINT j之前的事务修改数据块全部都写到数据文件中了.再看对之前的两个问题解决:
1,只要扫描最后一个CHECKPOINT记录之后提交和未交的REDO log entry就可以了,通过构建REDO和UNDO的列,只需要非常少的一部分就可以完成了;
2,在每个RLF进行SWITCH时,在最后都会生成一条CHECKPOINT记录,(DBWR的触发条件中有RFL SWITCH,最里层还是因为CHECKPOINT记录),那么扫描所有的文件,只要文件最后有CHECKPOINT记录,就表示该RLF的事务修改的数据块全部写到数据文件中了.继续扫描下一个文件;
3,可能会有人问直接使用COMMIT 记录代替CHECKPOINT记录不行吗?这样操作是不现实的,因为COMMIT记录会非常频繁,由于RB一般较小,,在事务COMMIT时把整个RB写出会非常快,如果还要同时写出BUFFER的脏数据块,那么性能开销非常大了;
CHECKPOINT受FAST_START_MTTR_TARGET参数控制,当然其他还有非常多的因素.现在我们来讨论这个参数,如果这个参数设得很小,那么ORACLE在进行实例恢复时更快可以完成.通过之前的讲解的CHECKPOINT机制来解释一下,因为FAST_START_MTTR_TARGET的值设置得越小,那么生成CHECKPOINT的记录也就越多,但是同时也会频繁的使DBWR进程写数据.所以这个参数需要根据各个因素综合考虑;
关于CHECKPOINT的具体方面可能还相当复杂,还涉及到其他的一些结构.但是这里说明了CHECKPOINT的基本原理.也算起一个抛砖引玉的作用吧.