buffer cache深度分析及性能调整(五)

4.2 buffer cache的统计信息

              为了对buffer cache进行性能的诊断,oracle提供了很多有关buffer cache的统计信息。这些统计信息

大致可以分成三类:1)有关用户发出的对内存数据块的请求相关的统计信息;2)有关DBWR后台进程对内存数据块处理相关的统计信息;3RAC相关的统计信息。

       我们在诊断buffer cache时,不需要关注所有的统计信息。这里主要介绍几个重要的统计信息,其他的统计信息都可以到《Oracle9i Database Reference: Appendix C》中找到。如下所示:

    SQL> SELECT name, value FROM v$sysstat  WHERE name in (

  2      'session logical reads',

  3      'physical reads',

  4      'physical reads direct',

  5      'physical reads direct (lob) ',

  6      'consistent gets',

  7      'db block gets',

  8      'free buffer inspected')

  9  /

NAME                                                                  VALUE

---------------------------------------------------------------- ----------

session logical reads                                                 73797

db block gets                                                           498

consistent gets                                                       73299

physical reads                                                        29017

free buffer inspected                                                     0

physical reads direct                                                    40

       这里做些简单的解释。

1)      session logical reads所有的逻辑读的数据块的数量。注意其中包括先从硬盘上读数据块到内存里再从内存里读数据块

2)      consistent gets在一致性consistent read读模式下读取的内存里的数据块数量。包括从rollback segment里读取的数据块数量以及从data block buffer里读取的数据块数量。主要是通过select产生的。Update/delete也能产生很少量的此类数据块。注意如果oracle的运行时间过长由于oraclebug导致consistent gets大大超过实际的数量。因此建议使用‘no work - consistent read gets’, ‘cleanouts only - consistent read gets’,‘rollbacks only - consistent read gets’, ‘cleanouts and rollbacks - consistent read gets’之和来代替consistent gets的值。

3)      db block gets:在当前(current)模式下读取的内存里的数据块的数量。不是读取过去某个时点的数据块,而必须是当前最新的数据块。主要是通过update/delete/insert来产生的,因为DML需要当前最新的数据块才能对之进行改变。在字典管理表空间下,一些获得当前可用扩展空间的select语句也会产生此类数据块,因为必须得到当前最新的空间使用信息才能扩展。逻辑上,session logical reads = consistent gets + db block gets

4)      physical reads:从硬盘里读取的数据块的数量。注意,这个数量大于实际从硬盘里读取的数量,因为这部分block也包括了从操作系统缓存里读取的数据块数量。

5)      physical reads direct:有些数据块不会先从硬盘读入内存再从内存读入PGA再传给用户,而是绕过SGA直接从硬盘读入PGA。比如并行查询以及从临时表空间读取数据。这部分数据块由于不缓存使得hit ratio不会被提高。

6)      physical reads direct (lob):与physical reads direct一样。

7)      free buffer inspected:这个值表示为了找到可用数据块而跳过的数据块的数量。这些被跳过的数据块就是脏的或被锁定的数据块。明显,这个值如果持续增长或很高,就需要增加buffer cache的大小了。

在获得了这些统计信息以后,我们可以计算buffer cache的命中率:

Hit Ratio = 1 – (physical reads – physical reads direct - physical reads direct (lob) ) / session logical reads

Miss ratio =  (physical reads – physical reads direct - physical reads direct (lob) ) / session logical reads

通常在OLTP下,hit ratio应该高于0.9。否则如果低于0.9则需要增加buffer cache的大小。在考虑

       调整buffer cache hit ratio时,需要注意以下几点。

1)      如果上次增加buffer cache的大小以后,没有对提高hit ratio产生很大效果的话,不要盲目增加buffer cache的大小以提高性能。因为对于排序操作或并行读,oracle是绕过buffer cache进行的。

2)      在调整buffer cache时,尽量避免增加很多的内存而只是提高少量hit ratio的情况出现。

我们还可以查询每种buffer cache的统计信息,主要关注的还是consistent_getsdb_block_gets以及

       physical_reads的值。

SQL> SELECT name, block_size,physical_reads, db_block_gets,consistent_gets

  2  FROM v$buffer_pool_statistics;

NAME                 BLOCK_SIZE PHYSICAL_READS DB_BLOCK_GETS CONSISTENT_GETS

-------------------- ---------- -------------- ------------- ---------------

DEFAULT                    8192          28978           719           77591

DEFAULT                   16384              2            80              11

v$sysstat中名称以DBWR开头的都是有关DBWR后台进程相关的统计信息。当DBWR进程写完脏数据块以后或者扫描完LRU链表以后更新这些统计信息。DBWR会基于被触发的频率以及所处理的内存数据块的数量与总内存数据块的数量的比例,来进行自我调整。我们可以通过这些统计信息得到一些对当前DBWR运行情况的认识。

4.3 buffer cache的等待事件

              buffer cache相关的等待事件包括:latch freebuffer busy waitsfree buffer waits。曾经发生过的等

待事件可以从v$system_event(一个等待事件对应一行记录)和v$session_event(一个session一个等待事件对应一行记录)中看到。而当前系统正在经历的等待事件可以从v$session_wait看到。

4.3.1 latch free等待

       等待事件“latch free”中与buffer cache有关的有两类:cache buffers chains latchcache buffers lru chain

latch。在理解了上面所描述的有关buffer cache的内部管理机制以后,就应该很容易理解这两个latch产生的原因。

       对于buffer cache中的每个hash chain链表来说,都会有一个名为cache buffers chains latchlatch来保护对hash chain的并发操作,这种latch通常也叫作hash latchCBC 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))

    ·位于2052131075 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大概对应8hash chain

SQL> select x.ksppinm, y.ksppstvl, x.ksppdesc

  2  from x$ksppi x , x$ksppcv y

  3  where x.indx = y.indx

  4  and x.ksppinm like '\_%' escape '\'

  5  and ksppinm like '%_db_block_hash_buckets%'

  6  ;

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 latchlatch free等待事件。

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

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

/

还有一个原因可能会引起cache buffers chains latch,就是热点数据块问题。这是指多个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_waitp1raw字段来判断latch free等待事件是否是由于出现了热点块。如果p1raw保持一致,那么说明session在等待同一个latch地址,系统存在热点块。当然也可以通过x$bhtch来判断是否出现了热点块,该值越高则数据块越热。

SQL> select sid, p1raw, p2, p3, seconds_in_wait, wait_time, state

  2  from   v$session_wait

  3  where  event = 'latch free'

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

             要解决热点块的问题,可以通过将热点块中的行分散到多个数据块中去,这样原来的热点块就变成了

多个数据块,这样被hash到同一个latch的几率就降低了。如果热点块属于表,则可以先将表的数据导出来,然后增加表的pctfree值,最后将数据再导入。如果热点块属于索引,则可以设定较高的 pctfree参数后,重建索引。注意,这会增加索引的高度。

通过前面我们已经知道,每个working set都会有一个名为cache buffers lru chainlatch(也叫做lru latch)来管理。任何要访问working set的进程都必须先获得cache buffers lru chain latchcache buffers lru chain latch争用也是由于低效的扫描过多的内存数据块的SQL语句引起的。调整这些语句以降低逻辑读和物理读。只要修改一下上面找引起cache buffers chains latchSQL语句即可找到这样的SQL语句。

select /*+ rule */ s.sql_text

from x$bh a,dba_extents b,

(select * from (select addr from v$latch_children

    where name = 'cache buffers lru chain' 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

/

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/9842/viewspace-399670/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/9842/viewspace-399670/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值