等待事件latch: cache buffers chains 的分析与优化
等待事件latch: cache buffers chains 的分析与优化
要理解latch: cache buffers chains并解决这个问题,就需要深入的了解Buffer Cache及其原理。
1、Buffer Cache概述
Buffer Cache是SGA的一部分,Oracle利用Buffer Cache来管理data block,Buffer Cache的最终目的就是尽可能的减少磁盘I/O。
内存中数据块的存放位置是记录在一个hash列表当中的。 当一个会话需要访问某个数据块时;它首先要搜索这个hash 列表;从列表中获得数据块的地址;然后通过这个地址去访问需要的数据块;这个列表 Oracle 会使用一个latch来保护它的完整性。 当一个会话需要访问这个列表时;需要获取一个Latch;只有这样;才能保证这个列表在这个会话的浏览当中不会发生变化。
2、如何定位数据块是否在buffer cache中
首先,通过对数据块所在的文件号和块号进行hash计算,算出对应bucket号(hash bucket)。
沿着对应hash bucket所在hash chain list访问链上的buffer header(bh,相关信息由x$bh视图描述),hash chain list上挂载了一或多个bh,bh与Data block一一对应。
3、latch:cache buffers chains出现的原因
3.1 不够优化的SQL
大量逻辑读的SQL语句就有可能产生非常严重的latch:cache buffers chains等待,因为每次要访问一个block,就需要获得该latch,由于有大量的逻辑读,那么就增加了latch:cache buffers chains争用的机率。 对于正在运行的SQL语句,产生非常严重的latch:cache buffers chains争用,可以利用下面SQL查看执行计划,并设法优化SQL语句。
select * from table(dbms_xplan.display_cursor(sql_id,plan_hash_value));
如果SQL已经运行完毕,我们就看AWR报表里面的SQL Statistics->SQL ordered by Gets->Gets per Exec,试图优化这些SQL。
示例:读库拉报表卡慢
分析SQL的执行计划,发现使用了MERGE JOIN CARTESIAN(笛卡尔积),执行计划如下:
SQL单次执行时间超过1小时,修改参数关闭笛卡尔积,然后SQL产生了新的执行计划,优化后执行时间不足1秒,该等待事件大部分可通过优化SQL解决。
3.2 热点块争用
1)查找数据库是否存在latch的争用
select sid,event,p1,p1raw from v$session_wait where event='latch: cache buffers chains';
2)下面查询查出Top 5 的争用的latch address。
select * from( select CHILD#,ADDR,GETS ,MISSES,SLEEPS from v$latch_children where name = 'cache buffers chains' and misses>0 and sleeps>0 order by 5 desc, 1, 2, 3) where rownum<=5;
3)然后利用下面查询找出Hot block。
SELECT
/*+ RULE */
E.OWNER
|| '.'
|| E.SEGMENT_NAME SEGMENT_NAME,
E.PARTITION_NAME,
E.EXTENT_ID EXTENT#,
X.DBABLK - E.BLOCK_ID + 1 BLOCK#,
X.TCH,
L.CHILD#
FROM SYS.V$LATCH_CHILDREN L,
SYS.X$BH X,
SYS.DBA_EXTENTS E
WHERE X.HLADDR='00000001F8C387C0'
AND E.FILE_ID = X.FILE#
AND X.HLADDR = L.ADDR
AND X.DBABLK BETWEEN E.BLOCK_ID AND E.BLOCK_ID + E.BLOCKS - 1
ORDER BY X.TCH DESC;
3.3 改嵌套循环为hash join
分析引起该等待事件的SQL的执行计划,发现使用了嵌套循环,执行计划如下:
可以通过hint使用/*+use_hash(t1 t2)*/指定关联方式,hash join主要适用于两表差距很大,小表可以完全放入内存情况。
3.4 Hash Bucket太少
需要更改_db_block_hash_buckets隐含参数。其实在Oracle9i之后,我们基本上不会遇到这个问题了,除非遇到Bug。所以这个是不推荐的,记住,在对Oracle的隐含参数做修改之前一定要咨询Oracle Support。
3.5 Latch太少
需要更改_db_block_lru_latches隐含参数,在10G之后,该参数默认为cpu_count的8倍,说明该参数依赖CPU配置,不建议自行修改。