[AD]数据缓冲历程概述

一,Buffer Cache原理
Buffer Cache是oracle的SGA中的一个重要部分,通常的数据访问都是在Buffer Cache中完成的。当一个进程需要访问数据时,首先需要确定数据在内存中是否存在,如果数据在Buffer Cache中存在,则需要根据数据的状态判 断是否可以直接访问还是需要构造一致性读取;如果数据在Buffer中不存在,则需要在Buffer Cache中寻找足够的空间以装载需要的数据,如果Buffer Cache中找不到足够的空间,则需要触发DBWR去写脏数据,释放Buffer空 间。
二,LRU与Dirty List
1,在Buffer Cache中,Oracle通过几个链表进行内存管理,其中最为熟知的是LRU List和Dirty List(也经常被称为Write List,从oracle 8i开始,因为算法的改变,也被称为CheckpointQueue),各种List上存放的是指向Buffer的指针。
2,LUR List用于维护内存中的Buffer,按照LRU算法进行管理,数据库初始化时,所有的Buffer都被Hash到LRU List上管理。当需要从数据文件上读取数据时,首先要在LRU List上寻找Free的Buffer,然后读取数据到BufferCache中,当数据被修改之后,状态变成Dirty,就可以被移动至DirtyList(CheckpointQueue),DirtyList上的都是候选的可以被DBWR写出到数据文件中的Buffer,一个Buffer要么在LRUList上,要么在DirtyList上存在,不可能同时存在于多个List。
三,BufferCache原理及使用


1,当一个server进程需要读数据到Buffer Cache中时,首先必须判断该数据在Buffer中是否存在(图中的1),如果存在且可用,则获取该数据,根据LRU算法在LRUList上移动该Block;如果Buffer中不存在该数据,则需要从数
据文件中读取。
2,在读取数据之前,Server进程需要扫描LRU List寻找Free的Buffer,扫描过程中Server进程会把发现的所有已经修改过的Buffer移动到Checkpoint Queue上(图中的2),这些DirtyBuffer随后可以被写出到数据文件。
3,如果CheckpointQueue超过了阀值,Server进程就会通知DBWn去写脏数据(图中的3):这也是DBWn写的一个条件,这个阀值曾经提到是25%,也就是当检查点队列超过25%满就会触发DBWn的写操作:
SQL> select kvittag,kvitval,kvitval,kvitdsc from x$kvit
  2  where kvittag='kcbldq';
KVITTAG                           KVITVAL    KVITVAL KVITDSC
------------------------------ ---------- ---------- ----------------------------------------------------------------
kcbldq                                 25         25 large dirty queue if kcbclw reaches this
a,如果Server进程扫描LRU超过了一个阀值仍然不能找到足够的Free Buffer,将停止寻找,转而通知DBWn去写出脏数据,释放内存空间。
b,同样地这个阀值可以从以上字典表中查询得到,这个数字是40%,也就是说Server进程扫描LRU超过40%还没能找到足够的FreeBuffer就会停止搜索,通知DBWn执行写出,这时进程会处于free busy wait等待。
SQL> select kvittag,kvitval,kvitval,kvitdsc from x$kvit
  2  where kvittag='kcbfsp';
KVITTAG                           KVITVAL    KVITVAL KVITDSC
------------------------------ ---------- ---------- ----------------------------------------------------------------
kcbfsp                                 40         40 Max percentage of LRU list foreground can scan for free
c,同时由于增量检查点的引入,DBWn也会主动扫描LRU List,将发现DirtyBuffer移至CheckpointQueue,这个扫描也受一个内部约束,在Oracle 9iR2中,这个比例也是25%。
SQL>  select kvittag,kvitval,kvitval,kvitdsc from x$kvit
  2   where kvittag='kcbdsp';
no rows selected
SQL>
4,找到足够大的Buffer之后,Server进程就可以将Buffer从数据文件读入BufferCache(图中的4)。
5,如果读取的Block不满足读一致性需求,则Server进程需要通过当前Block版本和回滚段构造前镜像返回给用户。
四,AUXILIARY List
1,从Oracle 8i开始,LRU List和Dirty List又分别增加了辅助List(AUXILIARY List),用于提高管理效率。引入辅助List之后,当数据库初始化时,Buffer首先存在LRU的辅助List上(AUXILIARY RPL_LST),当被使用后移动到LRU住List上(MAIN RPL_LST),这样当用户进程搜索FreeBuffer时,就可以从LRU-AUX List开始,而DBWR搜索Dirty Buffer时,则可以从LRU-Main List开始,从而提高了搜索效率和数据库性能。
2,可以通过如下命令转储Buffer Cache的内容,从而清晰地看到以上描述的数据结构:alter session set events 'immediate trace name buffers level 4';
3,不同的level转储的内容详细程度不一样,此命令可用级别主要有1~10个级,其中各级别的含义如下:
Level 1:仅包含Buffer Headers信息
Level 2:包含Buffer Headers和Buffer概要信息转储。
Level 3:包含Buffer Headers和完整Buffer内容转储。
Level 4:Level 1+Latch转储+LRU队列。
Level 5:Level 4+Buffer概要信息转储。
Level 6和Level 7:Level4 + 完整的Buffer内容转储。
Level 8:Level4+显示users/waiters信息。
Level 9:Level5+显示users/waiters信息。
Level 10:Level6+显示users/waiters信息。
4,转储只限于在测试环境中使用,转储的跟踪文件可能非常巨大,为获取完整的跟踪文件建议设置初始化参数max_dump_file_size 为UNLIMITED。
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE    10.2.0.1.0      Production
TNS for Linux: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
SQL> show parameter max_dump;
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
max_dump_file_size                   string      UNLIMITED
SQL> show parameter db_cache_size;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_cache_size                        big integer 0
SQL>
五,Cache Buffers Lru Chain闩锁竞争与解决
1,当用户进程需要读数据到Buffer Cache时,或Cache Buffer根据LRU算法进行管理时,就不可避免地扫描LRU List获取可用Buffer或更改Buffer状态,我们知道,Oracle的Buffer Cache是共享内存,可以为众多并发进程并发访问,所以在搜索的过程中必须获取Latch(Lacth是Oracle的一种串行锁机制,用于保护共享内存结构),锁定内存结构,防止并发访问损坏内存中的数据。这个用于锁定LRU的Latch就是常见到的Cache Buffer Lru Chain。
2,SQL> select addr,latch#,name,gets,misses,immediate_gets,immediate_misses from v$latch where name='cache buffers lru chain';
ADDR         LATCH# NAME                                                     GETS     MISSES IMMEDIATE_GETS IMMEDIATE_MISSES
-------- ---------- -------------------------------------------------- ---------- ---------- -------------- ----------------
2000944C        117 cache buffers lru chain                                 14443          0           1627                0
SQL>
Cache Buffers Lru Chain Latch存在多个Latch,其数量受隐含参数_db_block_lru_latches控制
3,SQL> @GetParDescrb.sql
Enter value for par: lru
old   3:  WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:  WHERE x.indx = y.indx AND x.ksppinm LIKE '%lru%'
NAME                           VALUE                DESCRIB
------------------------------ -------------------- ------------------------------------------------------------
_simulator_lru_rebalance_thres 10240                LRU list rebalance threshold (count)
h
_simulator_lru_rebalance_sizth 2                    LRU list rebalance threshold (size)
r
_simulator_lru_scan_count      8                    LRU scan count
_db_block_lru_latches          8                    number of lru latches
_gc_global_lru                 AUTO                 turn global lru off, make it automatic, or turn it on
4,可以从v$latch_children视图查看当前各个Latch使用情况。
5,SQL> select addr,child#,name,gets,misses,immediate_gets igets,immediate_misses immisses from v$latch_children where name='cache buffers lru chain';
ADDR         CHILD# NAME                                 GETS     MISSES      IGETS   IMMISSES
-------- ---------- ------------------------------ ---------- ---------- ---------- ----------
31D82B3C          1 cache buffers lru chain                12          0          1          0
31D82EC0          2 cache buffers lru chain                12          0          1          0
31D83244          3 cache buffers lru chain             14552          0       1620          0
31D835C8          4 cache buffers lru chain                12          0          1          0
31D8394C          5 cache buffers lru chain                12          0          1          0
31D83CD0          6 cache buffers lru chain                12          0          1          0
31D84054          7 cache buffers lru chain                12          0          1          0
31D843D8          8 cache buffers lru chain                12          0          1          0
8 rows selected.
6,如果该Latch竞争激烈,通常有如下方法可以采用。
a,适当增大BufferCache,这样可以减少读数据到BufferCache的机会,减少扫描LRU List的竞争。
b,可以适当增加LRU Latch的数量,修改_db_block_lru_latches参数可以实现,但是该参数通常来说是足够的,除非在Oracle Support的建议下或确知该参数将带来的影响,否则不推荐修改。
c,通过多缓冲池技术,可以减少不希望的数据老化和全表扫描等操作对于Default池的冲击,从而可以减少竞争。
六,Cache Buffer Chain 闩锁竞争与解决
在LRU和Dirty List这两个内存结构之外,Buffer Cache的管理还存在另外两个重要的数据结构:Hash Bucket和Cache Buffer Chain。
1,Hash Bucket和Cache Buffer Chain
如果所有的Buffer Cache中的所有Buffer都通过同一个结构管理,当需要确定某个Block在Buffer中是否存在时,将会遍历整个结构,性能会相当低下。为了提高效率Oracle引入了Bucket的数据结构,Oracle把管理的所有Buffer通过一个内部的Hash算法运算后,存放到不同Hash Bucket(n. 桶)中,这样通过Hash Bucket进行分割之后,众多的Buffer被分布到一定数量的Bucket之中,当用户需要在Buffer中定位数据是否存在时,只需要通过同样的算法获得Hash值,然后到相应的Bucket中查找少量的Buffer即可确定。每个Buffer存放的Bucket由Buffer的数据地址(DBA DataBlockAddress)运算决定。
2,Bucket内部,通过Cache Buffer Chain(Cache Buffer Chain是一个双项链表)将所有的Buffer通过Buffer Header 信息联系起来。
3,Buffer Header 存放的是对应数据块的概要信息,包括数据块的文件号、块地址、状态等。要判断数据块在Buffer中是否存在,通过检查bufferHeader即可确定。
4,如果大家去一个老点的图书馆,查找过手工索引,是这样的场景:树立在你面前的是一排柜子(那是相当壮观),柜子又被分为很多的小的抽屉,抽屉上按照不同的分类方法标注了相关信息,比如按开头字母顺序,如果要查询Oracle相关书籍,就需要找到标记有“O”的抽屉,打开抽屉,会看到一系列的卡片,这些卡片通常被一根铁闩串起来(通常就是一个铁丝),每张卡片上会记录相关书籍的信息,可能包括书籍名称、作者、ISBN号、出版日期等,当然这些卡片上会记录相关书籍的信息,就是书籍存放的书架位置信息,有了这个信息,通常翻阅这些卡片,就可以快速地找到我们想要的书籍,并且在需要时能够快速从图书馆浩如烟海的图书馆中找到我们需要的那一本。
5,在这里,图书馆就是我们Buffer Cache,这个Cache可能因为“图书数量”的增加而不断扩大,每个抽屉都是一个Bucket,这个Bucket中存放了根据一定的分类方式(也就是通过Hash运算)归入的图书信息,也就是
BufferCache;抽屉中的每张卡片就是一个BufferHeader,这些BufferHeader上记录了关于数据块的重要信息,如DBA等;这些卡片在Bucket中,通过一个铁闩串起来,这就是Cache Buffer Chain。
6,由于每个抽屉只有一根铁闩,如果很多的读者都想翻阅这个链上的卡片,那么就产生了CacheBufferChain的竞争,先来到的那个读者持有了Latch(n. 门闩)就能不听的翻阅,其他读者只好不停地来检查,当然如果检查次数多了(超过了_spin_count),也就可以去休息小憩一会,再来和其他读者争夺。
7,从Oracle 9i开始,对于Cache Buffer Chain的只读访问,其Latch可以被共享,也就是说,如果大家能只是翻一翻卡片,那么大家可以一起来看,但是如果有人要借走这本书,那么就只能独享这个Latch了。
这就是BufferCache和Latch的竞争。
8,由于Buffer根据BufferHeader进行散列,从而最终决定存入哪一个Hash Bucket,那么Hash Bucket的数量在一定程度上就决定了Bucket中的Buffer数量的多少,也就间接影响了搜索的性能。所以在不同版本中,Oracle一直在修改算法,优化Hash Bucket的数量。可以想象,Bucket的数量多一些,那么在同一时间就可以有更多的读者拿到不同的抽屉,进行数据访问;但是更多的抽屉,显然需要更多的存放空间,更多的管理成本,所以优化在什么时候都不是简单的一元方程。
9,SQL> select * from v$version where rownum < 2;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
10,SQL> @GetParDescrb.sql
Enter value for par: hash_buckets
old   3:  WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:  WHERE x.indx = y.indx AND x.ksppinm LIKE '%hash_buckets%'

NAME                           VALUE                DESCRIB
------------------------------ -------------------- ------------------------------------------------------------
_db_block_hash_buckets         65536                Number of database block hash buckets

11,SQL> show parameter db_block_buffers;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_buffers                     integer     0
SQL>
12,通过以上讨论知道,对应每个Bucket,只存在一个chain,当用户视图搜索Cache Buffer Chain时,必须首先获得Cache Buffer Chain Latch。那么Cache Buffer Chain Latch的设置就同样值得研究了。
在Oracle 8i之前,对于每一个Hash Bucket,Oracle使用一个独立的Hash Latch来维护,其缺省Bucket数量为next_prime(db_block_buffers/4)。
13,由于过于严重的热点块竞争,从Oracle 8i开始,Oracle改变了这个算法,首先Bucket数量开始增加,_db_block_hash_buckets增加到2*db_block_buffers,而_db_block_hash_latchs 的数量也发生了变化。
a,当Cache_Buffers 少于2052 Buffers:
_db_block_hash_latches = power(2,trunc(log(2,db_block_buffers-4)-1))
b,当Cache Buffers多于131075 Buffers:
_db_block_hash_latches = power(2,trunc(log(2,db_block_buffers-4)-6))
c,当Cache Buffers位于2052与131075Buffers之间:
_db_block_hash_latches=1024
13,从Oracle 8i开始,_db_block_hash_buckets 的数量较以前增加了8倍,而_db_block_hash_latches的数量较以前增加了8倍,而_db_block_hash_latches 的数量增加有限,这意味着,每个Latch需要管理多个Bucket,但是由于Bucket数量的多倍增加,每个Block的数量得以减少,从而使少量Latch管理更多的Bucket称为了可能。
七,ORACLE 8i的变化


1,从Oracle 8i开始,Bucket的数量比以前大大增加;通过增加的Bucket的“稀释”使得每个Bucket上的Buffer数量大大减少。
2,在Oracle 8i之前,_db_block_hash_latches的数量和Bucket的数量是一致的,每个Latch管理一个Bucket;从Oracle 8i开始每个Latch需要管理多个Bucket,由于每个Bucket上的Buffer数量大大降低,所以Latch的性能反 而得到了提高。
3,每个Bucket存在一条Cache Buffer Chain。
4,Buffer Header上存在指向具体Buffer的指针。
5,SQL> @GetParDescrb.sql
Enter value for par: hash_latches
old   3:  WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:  WHERE x.indx = y.indx AND x.ksppinm LIKE '%hash_latches%'
NAME                           VALUE                DESCRIB
------------------------------ -------------------- ------------------------------------------------------------
_db_block_hash_latches         1024                 Number of database block hash latches
SQL>
6,SQL> show parameter db_block_buffers;
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_buffers                     integer     0
SQL>
7,SQL> show parameter db_cache_size;
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_cache_size                        big integer 0
8,SQL> @GetParDescrb.sql
Enter value for par: bucket
old   3:  WHERE x.indx = y.indx AND x.ksppinm LIKE '%&par%'
new   3:  WHERE x.indx = y.indx AND x.ksppinm LIKE '%bucket%'
NAME                           VALUE                DESCRIB
------------------------------ -------------------- ------------------------------------------------------------
_simulator_bucket_mindelta     8192                 LRU bucket minimum delta
_lm_num_pt_buckets             4096                 number of buckets in the object affinity hash table
_lm_res_hash_bucket            0                    number of resource hash buckets
_parallel_fixwrite_bucket      1000                 Number of buckets for each round of fix write
_db_block_hash_buckets         65536                Number of database block hash buckets
_kgl_bucket_count              9                    index to the bucket count array
_cursor_stats_bucket           15                   Hash table buckets for cursor stats (2^).
7 rows selected.
SQL>
9,在trc文件中:/u01/app/oracle/admin/orcl/udump/orcl_ora_3184.trc
CHAIN: 6 LOC: 0x31cc0868 HEAD: [29fe986c,29fe986c]
    BH (0x29fe986c) file#: 1 rdba: 0x0040eb6a (1/60266) class: 1 ba: 0x29ca4000
      set: 3 blksize: 8192 bsi: 0 set-flg: 2 pwbcnt: 309
      dbwrid: 0 obj: 256 objn: 256 tsn: 0 afn: 1
      hash: [31cc0868,31cc0868] lru: [29fe9970,29fe9810]
      lru-flags:
      ckptq: [NULL] fileq: [NULL] objq: [307eadac,29feee54]
      st: XCURRENT md: NULL tch: 1
      flags:
      LRBA: [0x0.0.0] HSCN: [0xffff.ffffffff] HSUB: [65535]
      buffer tsn: 0 rdba: 0x0040eb6a (1/60266)
      scn: 0x0000.00164044 seq: 0x01 flg: 0x04 tail: 0x40440601
      frmt: 0x02 chkval: 0x7c1b type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x29CA4000 to 0x29CA6000
29CA4000 0000A206 0040EB6A 00164044 04010000  [....j.@.D@......]
29CA4010 00007C1B 00000002 00000100 00164044  [.|..........D@..]
29CA4020 00000000 00030002 00000000 00130008  [................]
29CA4030 000001EA 00800256 0001018C 0000C000  [....V...........]
29CA4040 00163FBF 001B0008 000001EA 00800257  [.?..........W...]
29CA4050 004D018C 00008000 00163FC2 03800000  [..M......?......]
29CA4060 00000004 01D800DA 0F0E10E6 00000000  [................]
29CA4070 0040EB6B 0040EB6C 00000000 00001F60  [k.@.l.@.....`...]
29CA4080 11C311B2 11E511D4 120711F6 12291218  [..............).]
29CA4090 124B123A 126D125C 128F127E 12B112A0  [:.K.\.m.~.......]
29CA40A0 12D312C2 12F512E4 13171306 13391328  [............(.9.]
29CA40B0 135B134A 137D136C 139F138E 13C113B0  [J.[.l.}.........]
29CA40C0 13E313D2 140513F4 14271416 14491438  [..........'.8.I.]
29CA40D0 146B145A 148D147C 14AF149E 14D114C0  [Z.k.|...........]
--More--(0%)

10,这个Chain中存在一个BH信息。注意其中包含hash: [31cc0868,31cc0868] lru: [29fe9970,29fe9810]
“hash: [31cc0868,31cc0868]”中两个数据分别代表X$BH中的NXT_HASH和PRV_HASH,也就是指同一个Hash Chain上的下一个BH地址和上一个Buffer地址。如果某个CHAIN只包含一个BH,那么这两个值将同时指向该Chain地址。
“lru: [29fe9970,29fe9810]”中的两个数据分别代表X$BH中的NXT_REPL和PRV_REPL,也就是LRU上的下一个Buffer和上一个Buffer。说Buffer_Cache是一个双向链表就是从这里实现的,从Oracle 8i开始,由于Bucket数量的增加,通常不容易见到包含多个BH的Bucket。
10,如果大量的进程对相同的Block进程进行操作,那么必然引发Cache Buffer Chain的竞争,也就是通常说的热点块的竞争。
八,X$BH余Buffer Header
1,Buffer Header数据,可以从数据字典中查询得到,这张字典表是X$BH。X$BH中的BH就是指Buffer Headers,每个Buffer 在X$BH中都存在一条记录。
SQL> select count(*) from X$bh;
  COUNT(*)
----------
      4595

SQL> show parameter db_block_buffers;
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_buffers                     integer     0
SQL>
2,Buffer Header中存储每个Buffer容纳的数据块的文件号、快地址、状态等重要信息,根据这些信息,结合dba_extents视图,可以很容易地找到每个Buffer对应的对象。
3,X$BH中还有一个重要的字段TCH,TCH为Touch的缩写,表示一个Buffer的访问次数,Buffer被访问的次数越多,说明该Buffer越“枪手”,也就可能存在热点块竞争的问题。
SQL> SELECT *
  2  FROM (SELECT addr,ts#,file#,dbarfil,dbablk,tch
  3  FROM x$bh
  4  ORDER BY tch DESC)
  5  WHERE ROWNUM<11;
ADDR            TS#      FILE#    DBARFIL     DBABLK        TCH
-------- ---------- ---------- ---------- ---------- ----------
B7FA7C14          0          1          1       1658        108
B7FA7C14          0          1          1       1657        107
B7FA7C14          0          1          1       1674        104
B7FA7C14          0          1          1         50         15
B7FA7C14          0          1          1        282         13
B7FA7C14          2          3          3       2740         12
B7FA7C14          0          1          1       2682         12
B7FA7C14          0          1          1         92         12
B7FA7C14          0          1          1       2074         12
B7FA7C14          0          1          1        250         12
10 rows selected.
SQL>
4,在结合dba_extents中的信息,可以查询得到这些热点Buffer都来自那些对象。
SQL> SElECT e.owner,e.segment_name,e.segment_type
  2  FROM dba_extents e,
  3  (SELECT *
  4    FROM (SELECT addr,ts#,file#,dbarfil,dbablk,tch
  5    FROM x$bh
  6    ORDER BY tch DESC)
  7   WHERE ROWNUM<11) b
  8  WHERE e.relative_fno=b.dbarfil
  9  AND e.block_id <=b.dbablk
 10  AND e.block_id + e.blocks >b.dbablk;
OWNER                          SEGMENT_NAME                   SEGMENT_TYPE
------------------------------ ------------------------------ ------------------
SYS                            JOB$                           TABLE
SYS                            JOB$                           TABLE
SYS                            I_SYSAUTH1                     INDEX
SYS                            I_SYSAUTH1                     INDEX
SYS                            I_JOB_JOB                      INDEX
SYS                            I_JOB_NEXT                     INDEX
SYS                            _SYSSMU1$                      TYPE2 UNDO
SYS                            _SYSSMU3$                      TYPE2 UNDO
SYS                            _SYSSMU6$                      TYPE2 UNDO
SYS                            _SYSSMU9$                      TYPE2 UNDO
10 rows selected.
5,除了查询X$BH之外,也可以从Buffer Cache转储信息中,看到Buffer Header的具体内容,可以用level 1 的级别进行转储。
6,在Oracle 10g之前,数据库的等待事件中,所有Latch等待被归入Latch Free等待事件中,在Statspack的report中,如果在Top5等待事件中看到Latch Free这一等待处于较高位置,就需要我们介入进行研究和解决。
7,由于Latch Free 是一个等待事件,我们需要从v$latch视图获得具体的Latch竞争主要是由哪些Latch引起的。在Statspack report中同样存在这样一部分数据。session的等待时间很容易从v$session_wait中查询得到。
SQL> select SID,SEQ#,EVENT from v$session_wait;

       SID       SEQ# EVENT
---------- ---------- ----------------------------------------------------------------
       140          9 Streams AQ: waiting for time management or cleanup tasks
       141          2 Streams AQ: qmn slave idle wait
       144      18247 SQL*Net message to client
       149          7 Streams AQ: qmn coordinator idle wait
       152          1 jobq slave wait
       155        117 rdbms ipc message
       156        812 rdbms ipc message
       160          6 rdbms ipc message
       161        610 rdbms ipc message
       162        113 rdbms ipc message
       163          6 rdbms ipc message

       SID       SEQ# EVENT
---------- ---------- ----------------------------------------------------------------
       164       3135 smon timer
       165       1861 rdbms ipc message
       166        933 rdbms ipc message
       167         94 rdbms ipc message
       168          7 rdbms ipc message
       169         85 rdbms ipc message
       170          7 pmon timer

18 rows selected.
8,如果需要具体确定热点对象,可以从v$latch_children中查询具体的子的Latch信息。
SQL> SELECT *
  2  FROM (SELECT addr,child#,gets,misses,sleeps,immediate_gets igets,
  3  immediate_misses imiss,spin_gets sgets
  4  FROM v$latch_children
  5  WHERE NAME='cache buffers chains'
  6  ORDER BY sleeps DESC)
  7  WHERE ROWNUM < 11;

ADDR         CHILD#       GETS     MISSES     SLEEPS      IGETS      IMISS      SGETS
-------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
31CC07C4          1        926          0          0         52          0          0
31CC0A40          2       2097          0          0         41          0          0
31CC0CBC          3        597          0          0         60          0          0
31CC0F38          4        720          0          0         44          0          0
31CC11B4          5        702          0          0         43          0          0
31CC1430          6        623          0          0         52          0          0
31CC16AC          7       1379          0          0         54          0          0
31CC1928          8        786          0          0         55          0          0
31CC1BA4          9        690          0          0         50          0          0
31CC1E20         10       1165          0          0         50          0          0
10 rows selected.
9,x$BH中还存在另外一个关键字段HLADDR,即Hash Chain Latch Address,这个字段可以和v$latch_children.addr进行关联,这样就可以把具体的Latch竞争和数据块关联起来,在结合dba_extents视图,就可以找到具体的热点竞争对象,找到具体热点对象之后,就可以结合v$sqlarea或者v$sqltext,找到频繁操作这些对象的SQL,然后对其进行优化,即可缓解或者解决热点块竞争的问题。通过以下查询可以实现以上思想,获取当前持有最热点数据块的Latch及Buffer信息。
SQL> SELECT b.addr,a.ts#,a.dbarfil,a.tch,b.gets,b.misses,b.sleeps
  2  FROM (SELECT *
  3  FROM (SELECT addr,ts#,file#,dbarfil,dbablk,tch,hladdr
  4  FROM x$bh
  5  ORDER BY tch DESC)
  6  WHERE ROWNUM < 11) a,
  7  (SELECT addr,gets,misses,sleeps
  8  FROM v$latch_children
  9  WHERE NAME='cache buffers chains') b
 10  WHERE a.hladdr = b.addr;

ADDR            TS#    DBARFIL        TCH       GETS     MISSES     SLEEPS
-------- ---------- ---------- ---------- ---------- ---------- ----------
31D2DF40          0          1        659       3654          0          0
31D251A4          0          1         58        875          0          0
31D1C408          0          1        648       3451          0          0
31D1A140          2          3         65       2141          0          0
31D08608          1          2         56       2647          0          0
31CFF5F0          2          3         72       1127          0          0
31CF6854          2          3         65       1295          0          0
31CE6FE4          2          3         56       1252          0          0
31CDBF80          2          3         65       1740          0          0
31CCBAA4          0          1        655       4829          0          0

10 rows selected.
10,利用前面提到的SQL,可以找到这些热点Buffer的对象信息。
SQL> SELECT distinct e.owner,e.segment_name,e.segment_type
  2  FROM dba_extents e,
  3  (SELECT *
  4  FROM (SELECT addr,ts#,file#,dbarfil,dbablk,tch
  5  FROM x$bh
  6  ORDER BY tch DESC)
  7  WHERE ROWNUM <11) b
  8  WHERE e.relative_fno=b.dbarfil
  9  AND e.block_id <= b.dbablk
 10  AND e.block_id + e.blocks > b.dbablk;

OWNER                          SEGMENT_NAME                   SEGMENT_TYPE
------------------------------ ------------------------------ ------------------
SYS                            SYS_C002066                    INDEX
SYS                            JOB$                           TABLE
SYS                            I_JOB_NEXT                     INDEX
SYS                            SYS_IOT_TOP_8802               INDEX
SYS                            SYS_IOT_TOP_8797               INDEX
SYS                            I_JOB_JOB                      INDEX
SYSMAN                         MGMT_FAILOVER_TABLE            TABLE
SYS                            SYS_IOT_TOP_8795               INDEX
8 rows selected.
11,结合v$sqltext和v$sqlarea,可以找到操作这些对象的相关SQL,继续查询
SQL> break on hash_value skip 1
SQL> SELECT /*+rule */ hash_value,sql_text
  2  FROM v$sqltext
  3  WHERE (hash_value,address) IN (
  4  SELECT a.hash_value,a.address
  5  FROM v$sqltext a,
  6  (SELECT DISTINCT a.owner,a.segment_name,a.segment_type
  7  FROM dba_extents a,
  8  (SELECT dbarfil,dbablk
  9  FROM (SELECT dbarfil,dbablk
 10  FROM x$bh
 11  ORDER BY tch DESC)
 12  WHERE ROWNUM <11) b
 13  WHERE a.relative_fno = b.dbarfil
 14  AND a.block_id <= b.dbablk
 15  AND a.block_id + a.blocks > b.dbablk) b
 16  WHERE a.sql_text LIKE '%'||b.segment_name||'%'
 17  AND b.segment_type='TABLE')
 18  ORDER BY hash_value,address,piece;

HASH_VALUE SQL_TEXT
---------- ----------------------------------------------------------------
 980205183 SELECT COUNT(*) FROM MGMT_FAILOVER_TABLE WHERE SYSDATE-LAST_TIME
           _STAMP > (HEARTBEAT_INTERVAL*4)/(24*60*60)

1267559359 SELECT COUNT(FAILOVER_ID) FROM MGMT_FAILOVER_TABLE WHERE SYSDATE
           -LAST_TIME_STAMP < :B1 /(24*60*60)
12,找到这些SQL之后,问题就简单了,可以通过优化SQL减少数据的访问,避免或优化某些容易引起争用的操作来减少热点块竞争。

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

转载于:http://blog.itpub.net/29611940/viewspace-1146005/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值