Oracle buffer cache与相关的latch等待事件

buffer cache与相关的latch等待事件 1.buffer cache 2.latch:cache buffers lru chain 3.latch:cache buffers chains 1.buffer cache 我的理解: buffer cache理解成4块结构: 三个列表+1个pool 三个列表指: lru (最近最少使用列表) dirty list (checkpoing qu

buffer cache与相关的latch等待事件

1.buffer cache
2.latch:cache buffers lru chain
3.latch:cache buffers chains

1.buffer cache

我的理解:
buffer cache理解成4块结构: 三个列表+1个pool
三个列表指:
    lru                        (最近最少使用列表)
    dirty list (checkpoing queue)
    hast bucket        (与latch:cache buffer chain相关)

一个pool指:
   buffer pool = db_cache_size / db_block_size

buffer pool:
内存中,数据存放的位置,每个pool的大小就是db_block_size大小.
比如,db_cache_size=800M,db_cache_size=8192,那么,buffer cache中包含的buffer pool 就有102400个(800*1024*1024/8192).

lru:
最近最少使用列表,一个顺序的清单,最上面为:MRU端(最常使用的对象),最下面为:LRU端(最不常用的对象)
在数据库初使化时,所有的buffer都被hash到LRU列表上管理;
当要从数据文件中读取数据时,首先要在LRU列表上查找free buffer,找到后才读取到buffer pool(即buffer cache)中.

dirty list:
脏数据列表,指向内存中需要写入数据文件的buffer pool的地址

hash bucket:
对于buffer pool,如果都通过一种结构管理,像从前面102400个pool中如果要找一个pool的话,性能会很低下.为了提高效率,oracle引入了 bucket结构,oracle将所有的buffer通过hash算法将buffer存放到不同的bucket上,用户需要定位buffer时,只用到 bucket中查找少量的buffer就可以找到.这样就提高了效率.

buffer cache的原理:
这个原理至关重要.

当一个Server进程需要读取数据到buffer cache中时:

1).首先要判断该数据是否存在于buffer中,如果存在,且可用.则获取数据,再根据LRU算法在LRU列表上移动该block;

2).如果数据不存在于buffer中,Server进程就要扫描lru列表,查找可用的buffer空间(free buffer)以放数据到buffer中,
在扫描lru list的过程中,如果碰到已经被修改过的buffer,就将它移动到dirty list(checkpoint queue)上(由于增量检查点的引入,DBWR进程也会主动扫描一定比例的LRU list,将发现的脏数据块移动到dirty lis);
如果dirty list(checkpoint queue)达到了阈值,Server进程就会通知DBWn进程写出脏数据到数据文件(DBWR进程写的一个触发条件);
如果Server进程扫描lru列表到一个阈值还没有找到足够的free buffer,这时,就停止对lru的扫描转而通知DBWR写出脏数据,释放内存空间;这时,进程处于free buffer wait等待.

3).找到足够的buffer之后,Server进程就可以将数据从数据文件读入到buffer cache中;

4).如果读取的block不满足"一致性"需求,则Server进程就需要通过当前block的版本从回滚段中读取该block的"一致性"镜像返回给用户(consistent gets).

2.latch:cache buffers lru chain

当用户读取数据到buffer cache中,或buffer cache根据LRU算法进行管理时,就不可避免的要扫描LRU列表以获取free buffer或更改buffer状态.
buffer cache为众多并发进程提供并发访问,所以在搜索的过程中,必须获取latch锁定内存结构,以防止并发访问对内存中的数据造成损坏.
这个用于锁定LRU的latch就是cache buffers lru chain.

cache buffers lru chain锁存器的默认数量:
DB_WRITER_PROCESSES <= 4        锁存器数= 4 * cpu数
DB_WRITER_PROCESSES > 4        锁存器数= db_writer_processes * cpu数
可以通过初始化参数_db_block_lru_latches来向上调整cache buffers lru chain锁存器的数量(不建议这么做,除非在oracle support的建议下)

如果这个latch竞争激烈:
(1) 适当增大buffer cache,这样可以减少读数据到buffer cache,减少扫描lru列表的次数

(2) 适当增加lru latch数量,修改_db_block_lru_latches参数.不建议这么做.

(3) 使用多缓冲池技术

3.latch:cache buffers chains

引起cache buffers chains争用的原因一:低效率的SQL语句

多个并发低效的SQL语句同时执行,都设法获得相同的数据集,就造成cache buffers chains的争用.
    调整高buffer_gets的SQL语句可以缓解这类问题.(较小的逻辑读意味着较少的latch get操作,从而减少锁存器争用并改善性能。)

引起cache buffers chains争用的原因二:热点块(最常见原因)
    判断是不是热块问题的常用方法检查latch free事件的p1raw参数值,如果p1raw是相同的锁存器地址,则表明是热块问题.

select sid,event,p1raw,p2,p3,seconds_in_wait,wait_time,state
    from v$session_wait
    where event = 'latch free';

如果要确定具体的热点块,就要查询v$latch_children,x$bh,dba_extents,根据子latch的信息确认热点块.
    v$latch_children.addr 与x$bh.hladdr相关联,可以确认子latch相关的块.
    再根据x$bh.dbarfil与dba_extents.relative_fno和x$bh.dbablk与dba_extents.block_id&&block_id+blocks关联,查到具体对象.

1> 查看cache buffers chains子latch情况:

SQL> select * from
(select addr,child#,gets,misses,sleeps,immediate_gets igets,immediate_misses imisses,spin_gets
         from v$latch_children
        where name = 'cache buffers chains'
order by sleeps desc
)
where rownum<11;

ADDR         CHILD#       GETS     MISSES     SLEEPS      IGETS    IMISSES SPIN_GETS
-------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
69B625BC        739    1056438         65         41        645          0         46
69A821BC          3    1115506         54         39        711          0         34
69B0A9BC        451    1476125         96         30        573          0         83
69A83EFC          9     207227        833         20        800          0        823
69AA573C        119     167852        635         14        592          0        628
69AB2DBC        163     860553         22         14        670          0         15
69B8C19C        876    1283643       1125         12        224          0       1118
69B03E7C        429     315851         53         11        413          0         47
69B1C47C        509     590733         18         11        689          0         14
69BADEBC        987     223777        208         11        529          0        201

2> 联合x$bh视图查出相关块信息

SQL> select b.addr,a.tch,a.ts#,a.dbarfil,a.dbablk,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;

ADDR            TCH        TS#    DBARFIL     DBABLK       GETS     MISSES     SLEEPS
-------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
69BB451C      17729          6          5    1277992     548061          0          0
69B92CDC      17729          6          5    1277991     581254          0          0
69B7149C      17729          6          5    1277990     534335          0          0
69B4FC5C      17729          6          5    1277989     534914          0          0
69B2E41C      17728          6          5    1277988    1087533          1          0
69B0CBDC      17726          6          5    1277987     538605          0          0

3> 联合dba_extents查出具体的数据对象

select distinct owner,segment_name,segment_type
from dba_extents a,
     (select * from (select addr,tch,ts#,file#,dbarfil,dbablk from x$bh order by tch desc)
       where rownum<11
     ) b
where a.relative_fno = b.dbarfil
and   a.block_id <= b.dbablk
and   a.block_id + blocks > b.dbablk;

4> 联合v$sqltext或v$sqlarea找出相关的SQL语句

select /*+ rule */ hash_value,sql_text
from v$sqltext
where (hash_value,address) in
      (select a.hash_value,a.address
         from v$sqltext a,
              (select distinct a.owner,a.segment_name,a.segment_type
                 from dba_extents a,
                      (select dbarfil,dbablk
                         from (select dbarfil,dbablk
                                 from x$bh
                               order by tch desc
                              )
                        where rownum<11
                      ) b
                where a.relative_fno = b.dbarfil
                  and a.block_id <= b.dbablk
                  and a.block_id + a.blocks > b.dbablk
               ) b
        where a.sql_text like '%'||b.segment_name||'%'
          and b.segment_type = 'TABLE'
       )
order by hash_value,address,piece;

上一篇:RabbitMQ小结


下一篇:MySQL中求年龄