oracle检查点队列与增量检查点(一)

2014-11-24 14:31:51 · 作者: · 浏览: 0
oracle检查点队列与增量检查点
今天是2013-09-04,这几天一直心里安顿不下来,今天还好了,可以自己安静的学习一下oracle,在此记录一下学习笔记。这篇文章我不知道在那转载的,一直都留在我的qq空间,我觉得还是非常棒的,另外我查看分析了一下相关内容,并做 了部分实验。这块内容我想应该是ocp考试知识点之一吧。
检查点的主要目的是以对 数据库的日常操作影响最小的方式刷新脏块。脏块不断的产生,如何将脏块刷新到磁盘中去呢?在8i之前, Oracle定期的锁住所有的修改操作,刷新Buffer cache中的所有脏块,这种刷新脏块的方式被称为完全检查点,这极大的影响了效率,从9i之后只有当关闭数据库时才会发生完全检查点。
从8i开始,Oracle增加了增量检查点的概念,增量检查点的主要宗旨就是定期的刷新一部分脏块。将脏块一次刷新完是不合理的,因为脏块不断产生,没有穷尽。像完全检查点那样停止用户所有的修改操作,将脏块刷新完再继续,这绝对会极大的影响性能。所有增量检查点的一次刷新部分块是脏块问题的最好解决办法。那么,每次刷新时,都刷新那些块呢?根据统计研究,根据块变脏的顺序,每次刷新那些最早脏的块,这种方式最为合理。为了实现这一点,Oracle在Buffer cache中又建立了一个链表,就是检查点队列。每个块在它变脏时,会被链接到检查点队列的末尾。就好像排队一样,9:00来的人站在第一位,9:05来的人排第二位,以后每来一个人都站在队伍的末尾,这个队伍就是按来到的时间顺序排列的一个队列。检查点队列就是这样,块在变脏时会被链到末尾。因此检查点队列是按块变脏的时间顺序,将块排成了一个队列。
如上图,检查点队列中的每一节点,都指向一个脏块。检查点队列每个节点中的信息其实非常少,就是记录对应块在Buffer cache中的地址,脏块对应的重做记录在日志文件中的位置,另外还有前一个节点、后一个节点的地址。检查点队列还有LRU、脏LRU,这些都是双向链表。双向链表就是在节点中记录前、后两个节点的地址。
检查点队列头部的块是最早变脏的,因此,Oracle会定期唤醒DBWn从检查点队列头开始,沿着检查点队列的顺序,刷新脏块。在刷新脏块的同时,仍可以不断的有新的脏块被链接到检查点队列的尾部。这个定期唤醒DBWn刷新脏块的操作,Oracle就称为增量检查点。
eg:
SQL> select kvittag,kvitval,kvitdsc from x$kvit where kvittag='kcbldq';
KVITTAG KVITVAL KVITDSC
---------------------------------------- ---------- ----------------------------------------------------------------
kcbldq 25 large dirty queue if kcbclw reaches this
SQL> select kvittag,kvitval,kvitdsc from x$kvit where kvittag='kcbfsp';
KVITTAG KVITVAL KVITDSC
---------------------------------------- ---------- ----------------------------------------------------------------
kcbfsp 40 Max percentage of LRU list foreground can scan for free
SQL> show user
USER is "SYS"
如上图,1、2、3号节点所指向的脏块已经被刷新为干净块。同时,又有两个块变脏,它们被链接到了检查点队列的末尾,它们是9号、10号节点。
检查点队列的头,又被称为检查点位置,Checkpoint postion,这些名称我们不必从字面上去理解。总之,检查点位置就是检查点队列头。检查点队列头节点(也就是检查点位置)的信息,Oracle会频繁的将它记录到控制文件中,而且会很频繁的记录。一般是每隔三秒,有一个专门的进程CKPT,会将检查点位置记录进控制文件。
如上图,当前的检查点位置是检查点队列的1号节点。又一个三秒到了,CKPT进程启动,将新的检查点位置记入控制文件:
新的检查点位置是4号节点,它对应当前变脏时间最早的脏块。1、2、3号节点已经从检查点队列中摘除了。因为它们对应的脏块已经不脏了。一般来说,控制文件中的检查点位置之后的块都是脏块。但是有时也例外,因检查点位置每三秒才会更新一次,就像上图,1、2、3号节点对应的脏块已经被刷新过了,但是由于三秒间隔没到,检查点位置还是指向1号节点。只有当三秒到后,检查点位置才会被更新到4号节点上。
关于检查点队列、检查点位置我们先说到这里,在全面的介绍什么是增量检查点之前,我们先说一下检查点队列的一个重要作用。
让我们先来总结一下用户修改块时,Oracle内部都发生了什么:
1.如果块不在Buffer cache,将块读入Buffer cache
2.先生成重做记录,并记入日志缓存,在用户提交时写到日志文件中
3.在Buffer cache中修改块
4.在Buffer cache中设置块的脏标志位,标志块变成脏块,同时在检查点队列末尾增加一个新节点,记录这个新脏块的信息,信息包括:脏块在Buffer cache中的位置,在步骤2时生成的与此脏块对应的重做记录位置。
5.用户提交后,将相应的重做记录从重做缓存写入日志文件。
我现在将日志补充到上面的图中:
就像上图,检查点队列的每个节点,都保存有脏块的地址和脏块对应的重做记录的编号。脏块在Buffer cache中的位置是随机的,用户不一定修改那个块。但重做记录是顺序生成的,就和检查点队列的排列顺序一样。因为,它们都是当块被修改而变脏时产生的。块A先被修改,块A的重做记录就排在前面,块B后被修改,块B对应的重做记录会被排在块A对应的重做记录的后面。和它们在检查点中的顺序是一样。每当数据库因异外而当机,比如异常死机、断电等等,Buffer cache中有许多脏块没来的及写到磁盘上。以图为例,比如说现在断电了,现在磁盘上还有7个脏块,它们里面有用户修改过的数据,Oracle已经将反馈信息“你的修改完成”发送给用户,用户也以为他们的修改完成了,将为一直保存到数据库中。但是,断然的断电,令这几个脏块中的数据丢失了,它们没来得及写到磁盘上。
Oracle如何解决这个问题呢?很简单,当数据库重新启动时,Oracle只需从控制文件中读出检查点位置,检查点位置中记