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;
|