关于buffer cache

参考文献

  1. 深入解析Oracle
  2. v$latch
  3. v$latch_children
一、计算机进程访问数据原理

当计算机进程需要访问数据时,会优先从内存中查找是否有想要的数据,若内存中没有,再从硬盘中读取相应的数据。这样设计是有原因的,因为计算机访问内存中数据的速率远高于访问硬盘中数据的速率,利用好内存中已有的缓存数据,可以大大提高计算机的运行效率。

二、Oracle对于buffer cache的管理

将buffer cache比作一部汉语字典,所有的buffer就是字典的具体内容,而buffer header就是字典目录里的字,buffer header记录了相应buffer的文件号、块地址、状态等信息,通过buffer header我们可以找到相应的buffer。但是当我们想要查找某一个字的信息时,总不能通过遍历所有字来先找到这个字,所以有了bucket,这个bucket就是字典里的拼音查找或者部首查找法,Oracler通过计算数据块地址(DBA)的哈希值来决定一个buffer块存放在哪个bucket中,同一个bucket中的cache组成了cache buffer chain。所以当Oracle进程需要访问数据时,先计算待访问数据的数据块地址的哈希值,通过该值找到对应的bucket,再从对应的bucket中查找数据的buffer header,最后通过buffer header在内存中找到要访问的数据。
但是,若待访问的数据在内存中不存在且无足够空间存放从磁盘读入的数据时,就需要用到LRU和LRUW链表,这俩链表也记录了buffer的buffer header,不同的是,LRU链表记录的是未被修改过的buffer信息,LRUW记录的是被修改过的buffer信息。Oracle会先扫描一遍LRU链表,将其中被修改过的buffer移到LRUW链表,随后调动DBWR将LRUW链表中的数据写入磁盘,释放buffer空间,以便读入新的数据。

三、 Cache buffer LRU chain

当进程需要读数据到buffer cache中时,会扫描更新LRU链表,当进程访问buffer cache中的数据时,也会通过LRU算法更新LRU链表。为了防止多个进程同时修改LRU链表,一个进程在更新LRU链表时必须先获得latch,这个用于锁定LRU的latch就是cache buffer lru chain。
查看cache buffer lru chain信息:

SET lines 2000 
col name FOR a30

SELECT addr,
       latch#,
       name,
       gets,
       misses,
       immediate_gets,
       immediate_misses
FROM   v$latch
WHERE  name = 'cache buffers lru chain';

查看各子latch使用情况:

SET lines 2000 col name FOR a20

SELECT addr,
       child#,
       name,
       gets,
       misses,
       immediate_gets   igets,
       immediate_misses imisses
FROM   v$latch_children
WHERE  name = 'cache buffers lru chain';
四、 Cache buffer chain

同一个bucket中的数据块连接成cache buffer chain,当有多个进程需要访问同一个bucket中的数据块时,若都是只读,则可以共享这个bucket的latch,共同访问其中的数据块,若有进程需要写入,则需要独自占有bucket的latch。

查询热点块
SELECT *
FROM   (SELECT addr,
               ts#,
               file#,
               dbarfil,
               dbablk,
               tch
        FROM   x$bh
        ORDER  BY tch DESC)
WHERE  rownum < 11;
查询热点块所属对象信息
SET lines 2000 
col owner FOR a20 
col segment_name FOR a40

SELECT e.owner,
       e.segment_name,
       e.segment_type,
       b.addr,
       b.ts#,
       b.file#,
       b.dbarfil,
       b.dbablk,
       b.tch
FROM   dba_extents e,
       (SELECT *
        FROM   (SELECT addr,
                       ts#,
                       file#,
                       dbarfil,
                       dbablk,
                       tch
                FROM   x$bh
                ORDER  BY tch DESC)
        WHERE  rownum < 11) b
WHERE  e.file_id = b.file#
       AND e.block_id <= b.dbablk
       AND e.block_id + e.blocks > b.dbablk;

将具体的latch竞争与热点块相关联

SET lines 2000

SELECT b.addr,
       a.ts#,
       a.dbarfil,
       a.dbablk,
       a.tch,
       b.gets,
       b.misses,
       b.sleeps
FROM   (SELECT *
        FROM   (SELECT addr,
                       ts#,
                       file#,
                       dbarfil,
                       dbablk,
                       tch,
                       hladdr
                FROM   x$bh
                ORDER  BY tch DESC)
        WHERE  rownum < 11) a,
       (SELECT addr,
               gets,
               misses,
               sleeps
        FROM   v$latch_children
        WHERE  name = 'cache buffers chains') b
WHERE  a.hladdr = b.addr;

将具体的latch竞争与热点块与具体的块信息关联

SET lines 2000 
col owner FOR a20 
col segment_name FOR a60

SELECT /*+ rule */ e.owner,
                   e.segment_name,
                   e.segment_type,
                   b.addr,
                   a.ts#,
                   a.dbarfil,
                   a.dbablk,
                   a.tch,
                   b.gets,
                   b.misses,
                   b.sleeps
FROM   dba_extents e,
       (SELECT *
        FROM   (SELECT addr,
                       ts#,
                       file#,
                       dbarfil,
                       dbablk,
                       tch,
                       hladdr
                FROM   x$bh
                ORDER  BY tch DESC)
        WHERE  rownum < 11) a,
       (SELECT addr,
               gets,
               misses,
               sleeps
        FROM   v$latch_children
        WHERE  name = 'cache buffers chains') b
WHERE  a.hladdr = b.addr
       AND e.file_id = a.file#
       AND e.block_id <= a.dbablk
       AND e.block_id + e.blocks > a.dbablk;
查询执行在热点块上具体的sql语句
SET lines 2000 
col owner FOR a20 
col segment_name FOR a60

SELECT /*+ rule */ hash_value,
                   sql_text
FROM   v$sqltext
WHERE  ( hash_value, address ) IN (SELECT s.hash_value,
                                          s.address
                                   FROM   v$sqltext s,
                                          (SELECT e.owner,
                                                  e.segment_name,
                                                  e.segment_type,
                                                  b.addr,
                                                  a.ts#,
                                                  a.dbarfil,
                                                  a.dbablk,
                                                  a.tch,
                                                  b.gets,
                                                  b.misses,
                                                  b.sleeps
                                           FROM   dba_extents e,
                                                  (SELECT *
                                                   FROM   (SELECT addr,
                                                                  ts#,
                                                                  file#,
                                                                  dbarfil,
                                                                  dbablk,
                                                                  tch,
                                                                  hladdr
                                                           FROM   x$bh
                                                           ORDER  BY tch DESC)
                                                   WHERE  rownum < 11) a,
                                                  (SELECT addr,
                                                          gets,
                                                          misses,
                                                          sleeps
                                                   FROM   v$latch_children
                                                   WHERE  name = 'cache buffers chains') b
                                           WHERE  a.hladdr = b.addr
                                                  AND e.file_id = a.file#
                                                  AND e.block_id <= a.dbablk
                                                  AND e.block_id + e.blocks > a.dbablk) abe
                                   WHERE  Upper(s.sql_text) LIKE '%'
                                                                 || abe.segment_name
                                                                 || '%'
                                          AND abe.segment_type = 'TABLE')
ORDER  BY hash_value,
          address,
          piece;

你可能感兴趣的:(关于buffer cache)