Saturday, January 10, 2009

Oracle检查点ckpt

全局检查点和增量检查点
http://blog.itpub.net/post/94/63495

由于Oracle中LGWR和DBWR工作的不一致,Oracle引入了检查点的概念,用于同步数据库,保证数据库的一致性。在Oracle里面,检查点分为两种:完全检查点和增量检查点。下面我们分别介绍这两种检查点的作用:

1、 完全检查点

在Oracle8i之前,数据库的发生的检查点都是完全检查点,完全检查点会将数据缓冲区里面所有的脏数据块写入相应的数据文件中,并且同步数据文件头和控制文件,保证数据库的一致。完全检查点在8i之后只有在下列两种情况下才会发生:

(1、)DBA手工执行alter system checkpoint的命令;

(2、)数据库正常shutdown(immediate,transcational,normal)。

由于完全检查点会将所有的脏数据库块写入,巨大的IO往往会影响到数据库的性能。因此Oracle从8i开始引入了增量检查点的概念。

2、 增量检查点

Oracle从8i开始引入了检查点队列这么一种概念,用于记录数据库里面当前所有的脏数据块的信息,DBWR 根据这个队列而将脏数据块写入到数据文件中。检查点队列按时间先后记录着数据库里面脏数据块的信息,里面的条目包含RBA(Redo Block Address,重做日志里面用于标识检查点期间数据块在重做日志里面第一次发生更改的编号)和数据块的数据文件号和块号。在检查点期间不论数据块更改几次,它在检查点队列里面的位置始终保持不变,检查点队列也只会记录它最早的RBA,从而保证最早更改的数据块能够尽快写入。当DBWR将检查点队列里面的脏数据块写入到数据文件后,检查点的位置也要相应地往后移,CKPT每三秒会在控制文件中记录检查点的位置,以表示Instance Recovery时开始恢复的日志条目,这个概念称为检查点的“心跳”(heartbeat)。检查点位置发生变更后,Oracle里面通过4个参数用于控制检查点位置和最后的重做日志条目之间的距离。在这里面需要指出的是,多数人会将这4个参数看作控制增量检查点发生的时间。事实上这是错误的,这4个参数是用于控制检查点队列里面的条目数量,而不是控制检查点的发生。

(1、)fast_start_io_target

该参数用于表示数据库发生Instance Recovery的时候需要产生的IO总数,它通过v$filestat的AVGIOTIM来估算的。比如我们一个数据库在发生Instance Crash后需要在10分钟内恢复完毕,假定OS的IO每秒为500个,那么这个数据库发生Instance Recovery的时候大概将产生500*10*60=30,000次IO,也就是我们将可以把fast_start_io_target设置为 30000。

(2、)fast_start_mttr_target

我们从上面可以看到fast_start_io_target来估算检查点位置比较麻烦。Oracle为了简化这个概念,从9i开始引入了 fast_start_mttr_target这么一个参数,用于表示数据库发生Instance Recovery的时间,以秒为单位。这个参数我们从字面上也比较好理解,其中的mttr是mean time to recovery的简写,如上例中的情况我们可以将fast_start_mttr_target设置为600。当设置了 fast_start_mttr_target后,fast_start_io_target这个参数将不再生效,从9i后 fast_start_io_target这个参数被Oracle废除了。

(3、)log_checkpoint_timeout

该参数用于表示检查点位置和重做日志文件末尾之间的时间间隔,以秒为单位,默认情况下是1800秒。

(4、)log_checkpoint_interval

该参数是表示检查点位置和重做日志末尾的重做日志块的数量,以OS块表示。

(5、)90% OF SMALLEST REDO LOG

除了以上4个初始化参数外,Oracle内部事实上还将重做日志文件末尾前面90%的位置设为检查点位置。在每个重做日志中,这么几个参数指定的位置可能不尽相同,Oracle将离日志文件末尾最近的那个位置确认为检查点位置。

http://space.itpub.net/35489/viewspace-524784

oracle 9i instance recovery
1. 增量检查点
在checkpoint queue的基础上实现了增量检查点,每3秒发生一次checkpoint heartbeat,记录dbwr上次写成功的最大RBA(redo block address)。这样的话做instance recovery的时候就从这个rba开始,而不是从上次checkpoint scn开始,大大节省了恢复时间。

2. twice scan of redo log
在应用redo之前,redo将会被操作两次,第一次去扫描哪些redo record需要被应用,因为9i在redo里添加了dbwr写数据块的信息,所以dbwr发生前的日志将不会被应用。第二步就是选出需要被应用的日志然后开始rollforward。

3. rollforward
在做instance recovery时必须先定位到redo log 然后应用所有日志到datafile,这时候包括了committed和uncommitted的数据。当做完rollward,数据库就可以open了。

4. rollback
因为rollforward产生了uncommitted数据,所以必须回滚这些数据。这将由smon和on-demand rollback来实现。smon将会扫描undo segment header去标志所有活动事务为dead,然后会逐渐去回滚这些事务。另外on-demand rollback提供了前台进程进行rollback,当前台进程企图获得被dead事务占用row lock,这时候前台进程将会去undo segment取得before image去回滚这个块,至于其他被这个dead事务lock的块就等待smon去回滚。

另外,如果在数据库打开的过程中process crash导致transaction dead,resource不能被释放的情况,这时候如果另一个进程需要这些resource,那么这个进程将会等待直到pmon清理dead process释放出resource。

如果数据库Crash,重新启动,很久远以前的未提交事务并不在Redo的恢复序列中。
但是未提交事务一定在回滚段事务表上存在,并且State=10,为活动事务。这就够了。

数据库启动之后,这些事务会被SMON逐个标记为Dead(不可能再活过来了),然后由SMON慢慢去回滚这些事务;也存在另外一种情况,后来的进程会去读这些未提交数据,发现Dead事务未提交,则主动进行回滚。

1. 一个数据块发生更新,必然写回滚
2. 回滚段的block变化也记录在redo中

一份未提交的数据必定在回滚中有相应的前镜像,任何正常的恢复都一定会把这些变化重新构建出来。


想像一下

1. update事务1更新了block 1
2. 回滚段1记录了block1的前镜像
3. checkpoint
4. update事务2更新了block2
5. 回滚段2记录了block2的前镜像
6. instance crash

现在重启数据库

1. 根据redo重新构建block2
2. 根据redo重新构建回滚段2
3. database open
4. SMON用回滚段2的数据回滚block2,SMON用回滚段1的数据回滚block1

最后一步也可能是
在另外一个select检索到block1或者block2的时候,发现这两个block的数据都是未提交的,此时再回滚block1和block2。

所以,只要有相应的回滚数据存在,无论什么时候oracle都可以找到一致的数据,oracle只需要知道这个事务是提交了的还是没提交了的,而这点在block header ITL中有记录。

http://roujiaweize.spaces.live.com/blog/cns!9745F14B4AEB3B72!328.entry
对SCN和CKPT的一点理解

scn (system change number,系统改变号),它提供 oracle 的内部时钟机制,定义数据库在某个确切时刻提交的版本,其作用是维护数据库的数据的一致性。


ckpt (checkpoint,检查点),它是一个数据库事件,它将已修改的数据从高速缓存刷新写入磁盘,并更新控制文件和数据文件。在一个检查点之后,重做日志文件中的重做记录对于崩溃/实例恢复不再有用。


控制文件为每个数据文件保存有一个:checkpoint scn, stop scn,只有数据文件中有 stop scn
select name,checkpoint_change#,last_change# from v$datafile;


系统检查点 scn (这个看别人写的,不懂)
select checkpoint_change# from v$database;
当一个检查点动作完成后,oracle 就把系统检查点的 scn 存储到控制文件中。


数据文件头:数据库 checkpoint scn
select name,checkpoint_change# from v$datafile_header;(这个是数据库正常打开时从控制文件中查的,因为数据库正常打开时这两个相等,数据文件头真正的 scn,oracle 自己读文件头)


控制文件为每个 redo 线程保存有一个:checkpoint scn
select thread#,checkpoint_change# from v$thread;


当一个检查点动作完成后,oracle 更新控制文件中的这些 checkpoint scn (控制文件中一个,所有数据文件头在控制文件中的存储,redo 在控制文件中的信息),以及数据文件头中的 checkpoint scn。所以可以理解,上面这些值都是从控制文件中取出来的。


当数据库用 normal 或者 immediate 选项关闭时,执行检查点,更新控制文件中数据文件的 stop scn,等于数据文件头中的 checkpoint scn。


下次启动数据库时,oracle 要进行两次检查。第一次看数据文件头中的 checkpoint scn 与控制文件中数据文件的 checkpoint scn。如果相等,进行第二次检查,检查数据文件头中的 checkpoint scn 与控制文件中数据文件的 stop scn。如果相等,不需要对这个文件恢复。每个数据文件都做这样的检查,然后打开数据库,将每个 stop scn 重新置为无穷大。


如果用 abort 关闭数据库,则不执行检查点处理,控制文件中数据文件的 stop scn 仍为无穷大。


下次启动时做两次检查。如第一次相等,再比较第二个。这时,数据文件头中的 checkpoint scn 一定是小于控制文件中数据文件的 stop scn 的,需要进行崩溃/实例恢复,进行前滚和回滚。


如果用备份代替了数据文件再启动数据库,这时做第一次检查时,数据文件头中的 checkpoint scn 一定小于控制文件中数据文件的 checkpoint scn;或者用备份的控制文件代替了控制文件再启动数据库,这时数据文件头中的 checkpoint scn 一定大于控制文件中数据文件的 checkpoint scn。只要这两个不相等,就需要介质恢复。


还有一种情况,如果控制文件和数据文件都是备份的,而这两个 checkpoint scn 正好相等,第一次比较通过,那么再看第二次比较了。其实这个时候在第一次比较之前,会先比较控制文件中 redo 线程的 checkpoint scn 的和 online log 的 scn,如果相等,继续,如果不相等(小于),提示控制文件是旧的需要介质恢复。

No comments: