重要概念:
DML和DDL语句都会产生两种不同类型的数据:
1、重做记录,保证数据库具有可恢复性。
2、被修改的数据块本身(包括撤销数据和真正想修改的数据),其目的是确保数据库的持久性。
这两类数据的临时存储地点和永久存储地点均不相同。
重做记录和被修改的数据块(我们称为脏数据块)走的是两条不同的道路,且是有一定的先后顺序的联系的。
重做记录产生后首先被写入日志缓冲区,然后不断的被LGWR进程刷入在线日志,再由ARCN进程写入归档文件。
当重做记录被写入日志缓冲区后,数据库按照重做记录在内存中对数据块进行修改,并按照重做记录中的RBA来排序存放到一个叫做检查点队列的结构中,这个时候数据块还没有写入数据文件当中,我们称这些数据块为脏数据块,当DBWn进程将这些脏数据写入数据文件后,我们说这些数据块变为干净的。
重做记录--->日志缓冲-->产生脏数据(提交操作除外)-->LGWR写入在线日志-->DBWn写入数据文件-->持久性完成
上面的顺序要排除提交操作,因为提交操作必须等待LGWR写入在线日志后,才能在内存中进行写入。
所以,根据以上的写入顺序,我们的数据文件永远比在线日志‘旧’,我们如何来确定数据文件比在线日志旧多少,就是检查点出现的原因。
参与检查点的进程有:LGWR,DBWn和CKPT ,分为两种:完全检查点和增量检查点:
发起一次完全检查点主要包括以下步骤:
1、在日志缓冲中获取当前最新的重做记录,做为检查点目标,记录下该重做记录的RBA和SCN。
2、LGWR清空缓存,将日志缓冲中的重做记录写入到在线日志中。
3、DBWn进程按照检查点目标,将该检查点目标以及之前的脏数据块按照检查点队列的顺序刷入到数据文件中。
4、最后,CKPT进程将检查点目标写入数据文件的头部和控制文件中。
这样,就可以判断数据文件头部的检查点目标到底是什么时候,最新的操作是哪个RBA了。
1、SCN与在线日志中重做记录的SCN比较,就可以知数据文件是否需要恢复。
2、如果数据文件需要恢复,RBA用来表示从哪个日志的哪一项重做记录开始恢复。
完全检查点发生的时机:
1、shutdown关闭数据库
2、执行alter systemcheckpoint
3、LGWR切换在线日志
4、执行部分表空间维护命令,altertablespace <表空间名>offline|online|begin backup|endbackup|read only|read write等,但此类检查点不完整,DBWn仅将特定表空间内的所有脏数据写回到数据文件。
完全检查点还分高优先级和低优先级,shutdown 与altersystem checkpoint是高优先级,检查点没有完成,命令不会返回。
我们为了观察检查点操作的时间和检查点目标,可以将初始化参数log_checkpoints_to_alert设置为true。
SQL>alter system checkpoint;
Systemaltered.
SQL>
以上会产生一个高优先级的完全检查点。对应的alert日志内容如下:
MonJul 22 09:36:34 2013
Beginningglobal checkpoint up to RBA [0xcf71.189b.10], SCN: 116338479648
Completedcheckpoint up to RBA [0xcf71.189b.10], SCN: 116338479648
可以看到改检查点目标为sequence为53105号重做日志的6299日志块中的第16字节,SCN为116338479648。
如果是低优先级的检查点。
比如
SQL>alter system switch logfile;
Systemaltered.
告警日志如下,命令返回了,但是检查点实际是没有完成的
MonJul 22 12:10:29 2013
Thread1 cannot allocate new log, sequence 53106
Privatestrand flush not complete
Current log# 6 seq# 53105 mem# 0:/u01/oracle/oradata/dipdb/redo06.log
Beginninglog switch checkpoint up to RBA [0xcf72.2.10], SCN: 116344746475
Thread1 advanced to log sequence 53106
Current log# 3 seq# 53106 mem# 0:/u01/oracle/oradata/dipdb/redo03.log
5分钟后,检查点完成
MonJul 22 12:15:17 2013
Completedcheckpoint up to RBA [0xcf72.2.10], SCN: 116344746475
目标检查点为53106号重做日志第2个日志块中的第16字节。该检查点目标位于切换后的重做日志中。
以下语句可以查询最近一次已完成的检查点SCN。
SQL>select FILE#,CHECKPOINT_CHANGE# fromv$datafile_header;
FILE# CHECKPOINT_CHANGE#
------------------------------------------------------------
1 116344746475
2 116344746475
3 116344746475
4 116344746475
5 116344746475
6 116344746475
7 116344746475
8 116344746475
9 116344746475
10 116344746475
11 116344746475
FILE# CHECKPOINT_CHANGE#
------------------------------------------------------------
12 116344746475
13 116344746475
14 116344746475
15 116344746475
16 116344746475
17 116344746475
18 116344746475
19 116344746475
27 116344746475
29 116344746475
30 116344746475
FILE# CHECKPOINT_CHANGE#
------------------------------------------------------------
31 116344746475
32 116344746475
24rows selected.
SQL>
增量检查点:
增量检查点是由ORACLE自动控制,也可以修改FAST_START_MTTR_TARGET影响其频率。
为什么要有增量检查点:
1、减少完全检查点时,DBWn进程的写入负担,将一部分脏数据先写入到数据文件中。
2、提高实例恢复速度。
第一点不难理解,第二点我们需要了解实例恢复的过程。
发生一次增量检查点的过程:
1、首先,确定一条重做记录(不是最新的),提取其RBA和SCN做为检查点目标,这条重做记录
与最新的重做记录是有‘距离’要求的,公式为:小于在线日志总和大小与最大的在线日志大小的差的
0.9倍。
2、LGWR将日志缓冲刷入在线日志
3、DBWn进程将检查点目标(RBA和SCN)产生的及检查点目标之前产生的脏数据块写入数据文件
4、最后,CKPT进程将检查点目标写入控制文件(没有写入数据文件)。
SQL>select a.CONTROLFILE_CHANGE#,
a.CHECKPOINT_CHANGE#,
a.CURRENT_SCN,
b.CHECKPOINT_CHANGE#
from v$database a, v$datafile_header b; 2 3 4 5
SQL>