Oracle latch: cache buffers chains

网友投稿 490 2022-11-30

Oracle latch: cache buffers chains

buffer cache深度分析之buffer cache的优化

buffer cache的等待事件     与buffer cache相关的等待事件包括:latch free、buffer busy waits、free buffer waits。曾经发生过的等待事件可以从v$system_event(一个等待事件对应一行记录)和v$session_event(一个session一个等待事件对应一行记录)中看到。而当前系统正在经历的等待事件可以从v$session_wait看到。latch free等待        等待事件“latch free”中与buffer cache有关的有两类:cache buffers chains latch和cache buffers lru chain latch。在理解了上面所描述的有关buffer cache的内部管理机制以后,就应该很容易理解这两个latch产生的原因。     对于buffer cache中的每个hash chain链表来说,都会有一个名为cache buffers chains latch的latch来保护对hash chain的并发操作,这种latch通常也叫作hash latch或CBC latch。数据库中会有很多的cache buffers chains latch,每个latch都叫做child cache buffers chains latch。一个child cache buffers chains latch会管理多个hash chain。前面我们知道,hash chain的数量由一个隐藏参数:_db_block_hash_buckets决定。同样也有一个隐藏参数:_db_block_hash_latches来决定有多少个cache buffers chains latch来管理这些hash chain。该参数的缺省值由buffer cache中所含有的内存数据块的多少决定,当内存数据块的数量      •少于2052个时,_db_block_hash_latches = power(2,trunc(log(2, 内存块数量 - 4) - 1))     •多于131075个时,_db_block_hash_latches = power(2,trunc(log(2, db_block_buffers - 4) - 6))     •位于2052与131075 buffers之间,_db_block_hash_latches = 1024 可以使用下面的SQL语句来确定当前系统的cache buffers chains latch的数量。

SQL> select count(distinct(hladdr)) from x$bh; COUNT(DISTINCT(HLADDR)) -----------------------  1024 SQL> select count(*) from v$latch_children where name='cache buffers chains';  COUNT(*) ----------  1024

在知道了cache buffers chains latch的数量以后,我们只需要用hash chain的数量除以latch的数量以后,就可以算出每个latch管理多少个hash chain了。我们将下面7532除以1024,就可以知道,当前的系统中,每个latch大概对应8个hash chain。

SQL> select x.ksppinm, y.ksppstvl, x.ksppdesc  2 from x$ksppi x , x$ksppcv y where x.indx = y.indx and x.ksppinm like '\_%' escape '\'  and ksppinm like '%_db_block_hash_buckets%' ; KSPPINM KSPPSTVL KSPPDESC ---------------------- -------- ------------------------------------- _db_block_hash_buckets 7523 Number of database block hash buckets

当数据库在hash chain搜索需要的数据块时,必须先获得cache buffers chains latch。然后在扫描hash chain的过程中会一直持有该latch,直到找到所要的数据块才会释放该latch。当有进程一直在扫描某条hash chain,而其他进程也要扫描相同的hash chain时,其他进程就必须等待类型为cache buffers chains latch的latch free等待事件。     不够优化的SQL语句是导致cache buffers chains latch的主要原因。如果SQL语句需要访问过多的内存数据块,那么必然会持有latch很长时间。找出逻辑读特别大的sql语句进行调整。v$sqlarea里那些buffer_gets/executions为较大值的SQL语句就是那些需要调整的SQL语句。这种方式不是很有针对性,比较盲目。网上曾经有人提供了一个比较有针对性的、查找这种引起较为严重的cache buffers chains latch的SQL语句的方式,其原理是根据latch的地址,到x$bh中找对应的buffer header,x$bh的hladdr表示该buffer header所对应的latch地址。然后根据buffer header可以找到所对应的表的名称。最后可以到v$sqltext(也可以到stats$sqltext)中找到引用了这些表的SQL语句。我也列在这里。where条件中的rownum<10主要是为了不要返回太多的行,只要能够处理掉前10个latch等待就能有很大改观。

select /**//*+ rule */ s.sql_text from x$bh a,dba_extents b, (select * from (select addr from v$latch_children  where name = 'cache buffers chains' order by sleeps desc) where rownum<11) c, v$sqltext s where a.hladdr = c.addr  and a.dbarfil = b.relative_fno  and a.dbablk between b.block_id and b.block_id + b.blocks  and s.sql_text like '%'||b.segment_name||'%' and b.segment_type='TABLE' order by s.hash_value,s.address,s.piece /

这是指多个session重复访问一个或多个被同一个child cache buffers chains latch保护的内存数据块。这主要是应用程序的问题。大多数情况下,单纯增加child cache buffers chains latches的个数对提高性能没有作用。这是因为内存数据块是根据数据块地址以及hash chain的个数来进行hash运算从而得到具体的hash chain的,而不是根据child cache buffers chains latches的个数。如果数据块的地址以及hash chain的个数保持一致,那么热点块仍然很有可能会被hash到同一个child cache buffers chains latch上。可以通过v$session_wait的p1raw字段来判断latch free等待事件是否是由于出现了热点块。如果p1raw保持一致,那么说明session在等待同一个latch地址,系统存在热点块。当然也可以通过x$bh的tch来判断是否出现了热点块,该值越高则数据块越热。

SQL> select sid, p1raw, p2, p3, seconds_in_wait, wait_time, state  from v$session_wait  where event = 'latch free'  order by p2, p1raw;  SID P1RAW P2 P3 SECONDS_IN_WAIT WAIT_TIME STATE ---- -------- --- --- --------------- ---------- ------------------  38 6666535C 13 1 1 2 WAITED KNOWN TIME  42 6666535C 13 1 1 2 WAITED KNOWN TIME  44 6666535C 13 3 1 4 WAITED KNOWN TIME ………………………  85 6666535C 13 3 1 12 WAITED KNOWN TIME  214 6666535C 138 1 1 2 WAITED KNOWN TIME

接下来,我们就可以根据p1raw的值去找到所对应的内存数据块以及对应的表的名称了。

select a.hladdr, a.file#, a.dbablk, a.tch, a.obj, b.object_name from x$bh a, dba_objects b where (a.obj = b.object_id or a.obj = b.data_object_id) and a.hladdr = '6666535C';

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Oracle Latch
下一篇:JAVA实战项目实现客户选购系统详细流程
相关文章

 发表评论

暂时没有评论,来抢沙发吧~