Benjamin Zhang

目前就职于中科院计算机网络信息中心,主要兴趣集中在数据库,操作系统,中间件。

【oracle】深入理解Buffer Cache和DBWR

14 Aug 2019 » oracle

深入理解Buffer Cache和DBWR

这篇文档指出哪些问题会影响Buffer CacheDBWR(database writer)的性能。如果出现如下等待事件的时候,这个文档就会有点作用。

  • latch争用,latch: cache buffers chainslatch: cache buffers chains
  • “平均写队列”average write queue长度过长
  • write complete waits等待的时间过长。
  • free buffer waitsBuffer busy wait等待的时间过长。

buffer cache

Buffer Cache是SGA区中专门用于存放从数据文件中读取的的数据块拷贝的区域。Oracle进程如果发现需要访问的数据块已经在buffer cache中,就直接读写内存中的相应区域,而无需读取数据文件,从而大大提高性能(内存的读取效率是磁盘读取效率的14000倍)

buffercache_01.png

在cache中的’dirty’ block是已经被更新了,但是还没有写入磁盘中的数据块。

buffer States

  • Unused : buffer目前没有被使用,可用状态。
  • clean : 之前被用过,但已写入磁盘,目前buffer中包含的数据块与磁盘的块是一致的版本。无需checkpoint,数据库可以pin the block并重用它。
  • Dirty : buffer中包含的块已经被修改,但是没有写入至磁盘,数据库需要checkpoint the block后,才能重用它。

每一个buffer有两个访问方式:pinned,free(unpinned)

  • pinned,说明目前buffer正在修改过程中,是为了user session访问它的时候,不至于 out of memory。别的user session不许动它。

LRU List与LRU Write List

buffer cache中的所有blocks都是放在LRU(least recently used)列表中。LRU是一个双向链表,LRU链表的两端有指针指向dirty buffer,另外的指针指向nondirty buffers。分别代表hot端和cold端,一个cold buffer代表最近没有使用的,一个hot buffer代表频繁访问和使用的。

当一个进程需要free buffer的时候,是从LRU的nondirty buffers这一端获取。

前面已经提到过了,如果一个用户进程发现某个block不在Cache中,那么用户进程就会从磁盘上将这个block读入Buffer Cache。在将block读入到Buffer Cache之前,首先要在LRU list上寻找Free的buffer,在寻找过程中,如果发现了Dirty Buffer就将其移动到 LRU Write List上。

SQL> column KVITDSC A40
SQL> column KVITDSC format A40
SQL> select kvittag,kvitval,kvitdsc from x$kvit where kvittag in('kcbldq','kcbfsp');

KVITTAG       KVITVAL KVITDSC
---------- ---------- ----------------------------------------
kcbldq             25 large dirty queue if kcbclw reaches this
kcbfsp             40 Max percentage of LRU list foreground ca
                      n scan for free

如果Dirty Queue超过了阀值25%,那么DBWn就会将Dirty Buffer写入到磁盘中。

如果当某个用户进程扫描LRU list超过40%都还没找到Free Buffer,那么这个时候用户进程将停止扫描LRU list,同时通知DBWn将Dirty Buffer写入磁盘,用户进程也将记录一个free buffer wait等待事件。如果我们经常看到free buffer wait等待事件,那么我们就应该考虑加大Buffer Cache了。

Latches:

  • Cache buffer chain latch:

    当在SGA中搜索数据块的时候需要获得一个latch。因为buffer cache就是一堆blocks的chain。当需要scan的时候,每一个chain都会受到latch的孩子节点保护。争用的产生,是对某一个块的very heavy access

  • Cache buffers LRU chain latch:

    当需要基于 LRU block replacement policy策略移动buffer的时候,需要上一个latch。避免其争用,可以增加buffer pools或者增加DB_BLOCK_LRU_LATCHES,LRU latches的个数(系统默认就已经足够了)。

SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ FROM x$ksppi x, x$ksppcv y
  2  WHERE x.inst_id = USERENV ('Instance')
  3  AND y.inst_id = USERENV ('Instance')
  4  AND x.indx = y.indx
  5  AND x.ksppinm LIKE '%db_block_lru_latches%';

NAME                             VALUE        DESCRIB
--------------------------------------------------------------------------------
_db_block_lru_latches            128          number of lru latches

Wait events:

  • Buffer busy wait:

    当多个会话尝试读取同一数据块或多个会话等待在同一数据块完成更改时,会引发。

  • Free buffer wait:

    这个引起的,是因为DBWR无法把buffer快速写出。

文献参考

参考网址:https://docs.oracle.com/cd/E11882_01/server.112/e40540/memory.htm#CNCPT1222

参考:https://www.cnblogs.com/ironyoda/p/6050141.html