当进程需要读取数据到buffer cache或cache buffer根据LRU算法进行管理,就会扫描LRU list获取可用buffer或更改buffer状态,此时在搜索过程中必须获取latch,锁定内存结构(latch是oracle的一种串行锁机制,保护共享内存结构),防止并发访问顺坏内存中的数据。
SQL> col name for a25
SQL> select addr,latch#,name,hash,gets,misses,immediate_gets,immediate_misses from v$latch where name='cache buffers lru chain';
ADDR LATCH# NAME HASH GETS MISSES IMMEDIATE_GETS IMMEDIATE_MISSES
-------- ---------- ------------------------- ---------- ---------- ---------- -------------- ----------------
03C43568 117 cache buffers lru chain 3559635447 118207 0 31831 0
Cache buffer lru chain latch存在多个子latch,其数量由隐含参数_db_block_lru_latches控制
查找隐含参数的sql
SQL> col ksppdesc for a25
SQL> col ksppstvl for a25
SQL> Select ksppinm name, ksppdesc, ksppstvl
2 from x$ksppi a, x$ksppcv b
3 Where a.indx = b.indx
4 and a.inst_id = userenv('instance')
5 and b.inst_id = userenv('instance')
6 and ksppinm = '_db_block_lru_latches'
7 ;
NAME KSPPDESC KSPPSTVL
------------------------- ------------------------- -------------------------
_db_block_lru_latches number of lru latches 8
以上脚本可以用于查询oracle中所有的隐含参数的脚本,只需要把后面的ksppinm值修改即可!
Select addr,latch#,child#,name,hash,gets,misses,immediate_gets,immediate_misses
from v$latch_children where name='cache buffers lru chain'
ADDR LATCH# CHILD# NAME HASH GETS MISSES IMMEDIATE_GETS IMMEDIATE_MISSES
-------- ---------- ---------- ------------------------- ---------- ---------- ---------- -------------- ----------------
2564E7AC 117 1 cache buffers lru chain 3559635447 12 0 0 0
2564EB5C 117 2 cache buffers lru chain 3559635447 12 0 0 0
------
8 rows selected
如果该latch竞争激烈,通常采取
1 增大buffer cache,增大缓存命中率,减少了LRU list扫描机会
2 增加db_block_lru_latches隐含参数,将产生多个cache buffers lru chain的子latch,减少竞争,不过该隐含_db_block_lru_latches静态参数一般是足够的,建议在oracle support建议或了解深入情况下修改。
3 通过多缓存池技术,db_recycle_cache_size和db_keep_cache_size可以减少不希望的数据老化和全表扫描对于default池的冲击,从而减少竞争!
用户请求查找相应数据会先查看buffer cache中是否存在相应的buffer,那么如何来确认是否存在相应buffer,如果直接遍历buffer cache,那么性能会相当低下!buffer cache的管理还存在hash bucket和cache buffer chain数据结构。
Oracle把管理的所有buffer通过一个内部的hash算法后,存放到不同的hash bucket中,每个hash bucket中都有一个cache buffer chain双向链表将hash bucket内的buffer header信息存储进来,buffer cache通过hash bucket分割之后,众多buffer就被分布到一定数量bucket之中,用户查找数据时只需要先通过hash运算得到相应的hash值然后到相应的hash bucket中查找cache buffer chain的buffer header来确定是否存在!
buffer hash存放的是数据块的概要信息,包括数据块文件号,块地址,状态等,判断数据是否在buffer cache存在,只需要检查buffer header即可确定,buffer header中存在只想具体buffer的指针!
这样如果某个数据块被获取先要获取这个数据块所在的cache buffer chain的latch,如果此时有别的session也在获取该latch,则其他session需要spin,如果spin次数超过_spin_count,也可以休眠sleep下然后再来竞争!
从oracle 9I开始,对于cache buffer chain的只读访问,latch可以被共享,但是如果修改就需要独享这个latch了!(latch由三种内存元素组成:pid(进程ID) 内存地址和内存长度,latch用于保存内存结构的完整性,对对象的访问安全控制是锁lock)
由于buffer根据buffer header进行散列hash运算然后存放于hash bucket,那么hash bucket数量一定程序决定了bucket中buffer多少,相应的hash bucket多点,那么hash
Bucket内的buffer就会少点,那么就能相应的减少cache buffer chain的latch竞争,不过更多的hash bucket则会需要更多的空间于管理成本!
Hash bucket的设置受隐含参数_db_block_hash_buckets的影响,对应每个bucket只存在一个chain,当用户在buffer cache中搜索数据块时,需要搜索相应的bucket的cache buffer chain,此时需要获取cache buffer chain latch,在oracle 8I之前,对于每个hash bucket,oracle使用一个独立的cache buffer hash latch维护,这样_db_block_hash_latches的数量和bucket是一致的。在oracle8I开始,_db_block_hash_buckets数量较以前增加了8倍,而db_block_hash_latchs数量增加有限,由于增加了bucket而减少了每个bucket上的buffer数量,则每个latch可以完全管理多个buckets。
上述的关于db_block_hash_buckets和db_block_hash_latch同样可以用上述的查找隐含参数的脚本查看相应信息!
热点块竞争:很多进程同时对相应的buffer所在的bucket的cache buffer chain访问,将产生cache buffer chain竞争,也就是所谓的热点块竞争!
x$bh数据字典表,也就是存放的buffer headers的信息,buffer header中存储buffer的数据块的文件号 块地址,状态等信息,根据这些信息结合dba_extents视图,可以很容易找到buffer对应的对象信息
其中的tch就是touch缩写,表示一个buffer的访问次数,buffer被访问的次数越多,该buffer所在的bucket内的cache buffer chain竞争越激烈,可能会存在热点块竞争问题。
Addr 地址 TS# 表空间号 file# 数据文件号 dbarfil 文件号 dbablk 数据块号
Tch 访问次数
nxt_hash:cache buffer chain内下一个buffer header编号
Prv_hash:cache buffer chain内下一个buffer header
Nxt_repl:LRU上的下一个buffer
PRV-repl:LRU上的上一个buffer
HLADDR hash chain latch address可以和v$latch_child.addr关联
查询热点块所在的owner和对象 类型
select e.owner,e.segment_name,e.segment_type 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.relative_fno=b.dbarfil and e.block_id<=b.dbablk and e.block_id+e.blocks>b.dbablk
在oracle 10g之前,数据库的等待事件中,所有latch等到被归入latch free等待事件,10g后,有些latch等待可能表现为单独的等待事件。
[@more@]来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/25362835/viewspace-1056772/ ,如需转载,请注明出处,否则将追究法律责任。