Oracle buffer cache 理解

Buffer cache 作为SGA中最重要的一部分之一,作用是用来缓冲数据块,原理是通过2个重要的链表实现:写链表和LRU链表(the least recently used)。写链表就是所有的脏数据块缓存(也就是说这一部分数据块被session修改过,还没有写入数据文件,此时的缓冲数据和数据块的数据是不一致的),而LRU链表指的是所有空闲的缓存,没有任何有用的数据,随时都可以使用。LRU链表的两端分为:最近使用端MRU(the most recently used)和最少使用端LRU。

  当一个session第一次访问一个数据块的时候,首先会在buffer cache中查找是否存在这个数据块的拷贝,也就是说会首先检查请求的数据块是否已经被缓存,如果已经缓存在buffer cache中,也就是命中cache hit,这时就直接从内存中读取该数据块。如果发现没有缓存该数据块,也就是未命中cache miss,此时就需要从数据块中读取到buffer cache中,然后才访问使用该块,这里可以引入一个比较重要的指标:命中率(命中次数与进程访问次数之比)。

 

SQL> select 1-(sum(decode(name, 'physical reads', value, 0))/(sum(decode(name, 'db block gets', value, 0))+(sum(decode(name, 'consistent gets', value, 0))))) "Buffer Hit Ratio" from v$sysstat; Buffer Hit Ratio ---------------- .926185625 1 row selected.

1

2

3

4

5

6

7

SQL> select 1-(sum(decode(name, 'physical reads', value, 0))/(sum(decode(name, 'db block gets', value, 0))+(sum(decode(name, 'consistent gets', value, 0))))) "Buffer Hit Ratio" from v$sysstat;

 

Buffer Hit Ratio

----------------

.926185625

 

1 row selected.

 

   如果数据块全部命中,说明我们访问使用的数据块全是逻辑读。如果没有未命中,则需要先将数据块移到内存中,这一步骤就是物理读,这时,oracle就会从空闲内存中分配一个适合大小的空闲缓存,如果空闲内存不够时,就会从LRU端开始查找LRU链表,直到找到一个可重用的缓存块或者达到最大查找块数的限制。在查找的过程中,如果发现脏数据块,会将这些数据块移到写链表中,然后继续查找。当找到空闲块时,就将我们需要访问使用的数据块缓存到查找的空闲块,并将这个块移到LRU链表的MRU端。如果此时达到最大查找块数的限制,还没有找到合适的空闲缓存时,进程会停止查找LRU链表,此时会通知DBWR进程将脏数据写入磁盘。

   当sql的访问方式是全表扫描的时候,需要读取表的所有块,并将块放在LRU链表的LRU端上,这里和上面稍有不同,不是放在MRU端,这样做的目的就是为了将全表扫描的块尽快移除LRU链表,因为全表扫描数据块多,且大部分的数据块很少使用。

  我们再看上面说的,如果达到最大查找块数的限制,就会停止查找LRU链表,通知DBWR进程写脏数据,如果一个系统中发现存在大量这样的脏缓存,在这样的情况下,用户进程访问一个数据块的过程可能比平时要长,效率也比较低,当然性能也会下降。在一定的系统中,可以使用命令清空所有的缓存:

 

alter system flush buffer_cache;

1

alter system flush buffer_cache;

 

注意这样的操作会清空系统的缓存,把所有的脏数据写入磁盘。

既然buffer cache用来缓存数据块,而从内存中读取数据又是最快的,那这个buffer cache的大小又是通过什么来控制?下面基于oracle 11g来简单阐述一下,通过制定db_cache_size来指定cache size,当然buffer cache也不是越大越好,通常建议大家:

DB_CACHE_SIZE = SGA_MAX_SIZE/2 ~ SGA_MAX_SIZE*2/3

   相信大家在数据库中都看见过这样的参数:DB_nK_CACHE_SIZE(DB_16K_CACHE_SIZE),n表示数据块的大小,这是oracle中非标准尺寸的数据块(标准大小是8K),当我们创建表空间的时候,可以指定blocksize的大小,这样这个表空间的所有数据块就按照blocksize执行的大小来存储(默认是8K),此时就可以通过DB_nK_CACHE_SIZE参数来指定缓存这个表空间数据块的buffer cache大小,每个尺寸的块只能缓存每个尺寸大小的块。当然参数不能设置重复,比如设定了db_cache_size的大小为4K,就不能设置db_4k_cache_size参数。在oracle 10G后,10g 后,指定了SGA_TARGET,就可以不需要指定Buffer Cache 的大小。

   可能大家有个疑问:如果有的数据块经常被访问,且数据块不大,这种情况是否可以常驻内存?答案当然是肯定的,对于这种访问频繁且大小比较小的数据块,可以设定常驻内存:

        1.保持缓冲池(Keep Buffer Pool )用于缓存那些永久驻入内存的数据块。它的大小由参数
DB_KEEP_CACHE_SZIE 控制;

        2.回收缓冲池(Recycle Buffer Pool)会立即清除那些不在使用的数据缓存块。它的大小由参数DB_RECYLE_CACHE_SIZE 指定;

        3.默认的标准缓存池,也就是上面所说的DB_CACHE_SIZE 指定。

  以上的3个参数设置之后就相互独立,且只适用于标准块尺寸的数据块。

关于buffer cache,现在应该对buffer cache有所了解了吧。还有更多关于buffer cache的内容这里就不深入探究了,请关注后期内容。

你可能感兴趣的:(Oracle)