latch: cache buffers chains 等待争用

“latch: cache buffers chains”争用通常会遇到,原因是当 SQL 语句读取比它们需要的多的缓冲区,并且多个会话正在等待读取同一个块时

如果竞争很激烈的话,则需要查看执行缓冲区获取次数最多的语句,然后查看这些语句的访问路径以确定这些语句的执行效率是否如您所愿。

典型的解决方法如下:

  • 查找访问相关块的 SQL 并确定是否需要重复读取。 这可能在单个会话中或跨多个会话。
  • 检查执行计划不是最优的 SQL(这是该等待事件的最常见原因)- 查看正在运行的 SQL 的执行计划并尝试减少每次执行对缓冲区获的获取,这将最大限度地减少被访问的块数,从而减少多个会话争夺同一个块的机会。
  • 如果您可以识别出一个糟糕的 SQL 并确定了一个更好的计划,您可以通过以下文章指导优化器使用该计划:

    Document 1400903.1 Directing Plans with Baselines/Profiles Using coe_load_sql_baseline.sql / coe_load_sql_profile.sql (shipped with SQLT)

SOLUTION

Possible hot blocks in the buffer cache normally can be identified by a high or rapid increasing wait count on the CACHE BUFFERS CHAINS latch. This latch is acquired when searching for data blocks cached in the buffer cache. The Buffer cache is implemented as a chain of blocks linked together under a hash value. When a buffer is requested the hash value of the chain that this buffer will be in is calculated and that chain is scanned. Each chain is protected by a latch to prevent it from being changed while it is scanned. Contention in this latch can be caused by very heavy access to a single block. This can require the application to be reviewed.

By examining the waits for this latch, information about the segment and the specific block can be obtained using the following queries.

Identify high contention latch addresses

First determine which latch addresses (ADDR) are interesting by examining the number of  sleeps for this latch. The higher the sleep count, the more processes are having to wait for that latch, so the higher the sleeps, the higher the contention. If we are investigating contention, the higher the sleeps the more interesting the latch addresses (ADDR) is. The following select returns latch addresses (ADDR) ordered by sleeps:

select *from v$latch; 19C 1000多个




SELECT child# "cCHILD" ,
  addr "sADDR" ,
  gets "sGETS" ,
  misses "sMISSES" ,
  sleeps "sSLEEPS"                ----获取不到就sleep 等待
FROM v$latch_children
WHERE name = 'cache buffers chains'
ORDER BY 5,  1,  2,  3;


Run the query above a few times to establish the addresses (ADDR) that consistently has the highest sleeps.

Identify the blocks protected under that address

Once the addresses (ADDR) with the highest sleep count have been determined, these latch addresses can be used to get more detail about the blocks currently in the buffer cache protected by this latch. The following query identifies the blocks protected by a particular ADDR and should be run just after determining the ADDR with the highest sleep count:

SQL>  column segment_name format a35
SELECT  /*+ RULE */
  e.owner  || '.'  || e.segment_name segment_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 = '&ADDR'
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 ;

Example Output:

SEGMENT_NAME                     EXTENT#      BLOCK#       TCH    CHILD# 
-------------------------------- ------------ ------------ ------ ---------- 
.EMP_PK                                5          474     17      7,668 
.EMP                                   1          449      2      7,668


The TCH column identifies the number of times each block has been hit by a SQL statement, so you can use this information to identify a hot block. The higher the value of the TCH column, the more frequent the block is accessed by SQL statements.

The following query joins with DBA_OBJECTS to find the objects waiting, the misses, sleeps, etc:

WITH bh_lc AS
  (SELECT
    /*+ ORDERED */
    lc.addr,
    lc.child#,
    lc.gets,
    lc.misses,
    lc.immediate_gets,
    lc.immediate_misses,
    lc.spin_gets,
    lc.sleeps,
    bh.hladdr,
    bh.tch tch,
    bh.file#,
    bh.dbablk,
    bh.class,
    bh.state,
    bh.obj
  FROM x$kslld ld,
    v$session_wait sw,
    v$latch_children lc,
    x$bh bh
  WHERE lc.addr  =sw.p1raw
  AND sw.p2      = ld.indx
  AND ld.kslldnam='cache buffers chains'
  AND lower(sw.event) LIKE '%latch%'
  AND sw.state ='WAITING'
  AND bh.hladdr=lc.addr
  )
SELECT bh_lc.hladdr,
  bh_lc.tch,
  o.owner,
  o.object_name,
  o.object_type,
  bh_lc.child#,
  bh_lc.gets,
  bh_lc.misses,
  bh_lc.immediate_gets,
  bh_lc.immediate_misses,
  spin_gets,
  sleeps
FROM bh_lc,
  dba_objects o
WHERE bh_lc.obj = o.object_id(+)
UNION
SELECT bh_lc.hladdr,
  bh_lc.tch,
  o.owner,
  o.object_name,
  o.object_type,
  bh_lc.child#,
  bh_lc.gets,
  bh_lc.misses,
  bh_lc.immediate_gets,
  bh_lc.immediate_misses,
  spin_gets,
  sleeps
FROM bh_lc,
  dba_objects o
WHERE bh_lc.obj = o.data_object_id(+)
ORDER BY 1,2 DESC;

 
The output is something similar to the following:

HLADDR           TCH   OWNER    OBJECT_NAME               OBJECT_TYP CHILD#  GETS   MISSES IMMEDIATE_GETS   IMMEDIATE_MISSES SPIN_GETS SLEEPS
---------------- ----- -------- ------------------------- ---------- ------- ------ ------ ---------------- ---------------- --------- ------
0000000621ED8B00   127 SABXFER  PCBDEMPRELEVEMENT         TABLE        80750 703326   1649             8007                0      1642      7
0000000621ED8B00   127                                                 80750 703326   1649             8007                0      1642      7
0000000621ED8B00    74 SABXFER  V_HIERARCHIEENTREPRISE_B  TABLE        80750 703326   1649             8007                0      1642      7
0000000621ED8B00     1 SABXFER  SACNTPR_PK                INDEX        80750 703326   1649             8007                0      1642      7
0000000621ED8B00     1 SABXFER  SAENCR2_1                 TABLE        80750 703326   1649             8007                0      1642      7
0000000621ED8B00     1                                                 80750 703326   1649             8007                0      1642      7
0000000621ED8B00     0                                                 80750 703326   1649             8007                0      1642      7


 

Reducing contention

In order to reduce contention for this object the following mechanisms can be put in place:

  1. Examine the application to see if the execution of certain DML and SELECT statements can be reorganized to eliminate contention on the object. This may be because individual SQL statements are reading more buffers than they need to or SQL affecting specific buffers does so at the same time. For more details see:

    Document 1342917.1 Troubleshooting 'latch: cache buffers chains' Wait Contention

  2. Decrease the buffer cache. If less buffers are stored then there is less change of them contending. This may only help in a small amount of cases and may just move the problem elsewhere.
  3. DBWR throughput may have a factor in this as well because this determines how quickly buffers are flushed to disk. If dirty buffers are present then processes requesting those buffers may need to find earlier version meaning that they hold latches longer increasing the chances of contention.  If using multiple DBWR's then increase the number of DBWR's. See:

    Document 62172.1 - Understanding and Tuning Buffer Cache and DBWR

  4. Increase the PCTFREE for the table storage parameters via ALTER TABLE or rebuild. This will result in less rows per block such that there is less chance of the same buffers being requested by processes.
  5. Consider implementing reverse key indexes (if range scans aren't commonly used against the segment)

你可能感兴趣的:(服务器,数据库,运维)