[ORACLE] oracle Buffer Cache 之Hash Bucket与Hash Chain List(cache bufferschain)
Posted A running snail,little step ev
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ORACLE] oracle Buffer Cache 之Hash Bucket与Hash Chain List(cache bufferschain)相关的知识,希望对你有一定的参考价值。
Hash Bucket 和 Cache Buffer Chain
ORACLE 将buffer cache中所有的buffer通过一个内部的Hash算法运算之后,将这些buffer放到不同的 Hash Bucket中。每一个Hash Bucket中都有一个Hash Chain List(也叫:cache buffers chain),通过这个list,将这个Bucket中的block串联起来。对应每个Bucket,只存在一个Chain,当用户试图搜索Cache Buffer Chain时,必须首先获得Cache Buffer Chain Latch
X$BH 与 Buffer Header
SQL> set linesize 50 SQL> desc x$bh Name Null? Type ----------------------- -------- ---------------- ADDR RAW(8) ---block在buffercache中的address INDX NUMBER INST_ID NUMBER CON_ID NUMBER HLADDR RAW(8) --(Hash Chain Latch Address)latch:cache buffers chains 的地址
--这个字段可以和 v$latch_child.addr 进行关联,这样就可以把具体的 Latch 竞争和数据块关联起来,再结合dba_extents 视图,就可以找到具体的热点竞争对象。
--到具体热点竞争对象之后,可以进一步地结合 v$sqlarea 或者 v$sqltext 视图,找到频繁操作这些对象的 SQL,对其进行优化,就可以缓解或解决热点块竞争的问题。 BLSIZ NUMBER NXT_HASH RAW(8) ---指向同一个Hash Chain List的下一个block地址 PRV_HASH RAW(8) ---指向同一个HashChain List的上一个block地址 NXT_REPL RAW(8) ---指向LRU list中的下一个block地址 PRV_REPL RAW(8) ---指向LRUlist中的上一个block地址 ...... TS# NUMBER FILE# NUMBER ...... TCH NUMBER --表征一个Buffer的访问次数,Buffer访问次数越多,说明该Buffer越“抢手”,也就越可能存在热点块竞争的问题 ......
查询可以获得当前数据库最繁忙的Buffer:
SQL> set linesize 200 SQL> select * from (select addr,ts#,file#,dbarfil,dbablk,tch from x$bh order by tch desc) where rownum<11; ADDR TS# FILE# DBARFIL DBABLK TCH ---------------- ---------- ---------- ---------- ---------- ---------- 00007F8DD59D2718 0 1 1 51224 255 00007F8DD59D2128 0 1 1 51217 255 00007F8DD59D2718 0 1 1 3917 255 00007F8DD59D2128 0 1 1 48233 255 00007F8DD59D5920 0 1 1 21927 255 00007F8DD59D57A0 0 1 1 3915 255 00007F8DD59D2128 0 1 1 20846 255 00007F8DD59D2128 0 1 1 13657 255 00007F8DD59D2718 0 1 1 51200 255 00007F8DD59D22A8 0 1 1 48234 255 10 rows selected.
查询得到这些热点Buffer都来自哪些对象:
SQL> col OWNER for A20 SQL> select e.owner,e.segment_name,e.segment_type from dba_extents e, (select * from (select addr,ts#,file#,dbarfil,dbablk,tch from x$bh order by tch desc) where rownum<11) b where e.relative_fno=b.dbarfil and e.block_id<=b.dbablk and e.block_id+ 2 3 e.blocks>b.dbablk; OWNER SEGMENT_NAME SEGMENT_TYPE -------------------- -------------------------------------------------------------------------------------------------------------------------------- ------------------ SYS C_FILE#_BLOCK# CLUSTER SYS C_FILE#_BLOCK# CLUSTER SYS C_FILE#_BLOCK# CLUSTER SYS C_FILE#_BLOCK# CLUSTER SYS C_FILE#_BLOCK# CLUSTER SYS C_FILE#_BLOCK# CLUSTER SYS C_FILE#_BLOCK# CLUSTER SYS C_FILE#_BLOCK# CLUSTER SYS C_FILE#_BLOCK# CLUSTER SYS C_FILE#_BLOCK# CLUSTER 10 rows selected.
每个Buffer对应x$bh中一条记录,Hash Chain List就是由x$bh中的NXT_HASH,PRV_HASH 这2个指针构成了一个双向链表,通过NXT_HASH,PRV_HASH这2个指针,那么在同一个Hash Chain List的block就串联起来了。
由于 Buffer 根据 Buffer Header 进行散列,最终决定存入那一个 Hash Bucket,那么 Hash Bucket 的数量在一定程度上决定了每个 Bucket 中 Buffer 数量的多少,也就间接影响了搜索的性能。所以在不同版本中,Oracle 一直在修改算法,优化 Hash Bucket 的数量。我们可以想象,
SQL> select BANNER_FULL from v$version; BANNER_FULL ---------------------------------------------------------------------------------------------------------------------------------------------------------------- Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.3.0.0.0
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ FROM x$ksppi x,x$ksppcv y WHERE x.inst_id =USERENV (\'Instance\') AND y.inst_id =USERENV (\'Instance\') AND x.indx = y.indx AND x.ksppinm LIKE\'%_db_block_hash%\'; NAME VALUE DESCRIB ----------------------------------------------------------------------- _db_block_hash_buckets 262144 Number of database block hash buckets _db_block_hash_latches 2048 Number of database block hash latches SQL> select count(distinct hladdr) from x$bh ; COUNT(DISTINCTHLADDR) --------------------- 2048 SQL> select count(*) from v$latch_children a,v$latchname b where a.latch#=b.latch# and b.name=\'cache buffers chains\'; COUNT(*) ---------- 2048
验证
SQL> select * from(select hladdr,count(*) from x$bh group by hladdr) where rownum<=5; HLADDR COUNT(*) ---------------- ---------- 00000000A80CE028 25 00000000A80CE0F0 31 00000000A80CE1B8 40 00000000A80CE280 18 00000000A80CE348 17 SQL> select hladdr,obj,dbarfil,dbablk,nxt_hash,prv_hash from x$bh where hladdr=\'00000000A80CE028\' order by obj; HLADDR OBJ DBARFIL DBABLK NXT_HASH PRV_HASH ---------------- ---------- ---------- ---------- ---------------- ---------------- 00000000A80CE028 2 1 12226 00000000A80CEC68 00000000A80CEC68 00000000A80CE028 64 1 114311 00000000A80CE828 00000000A80CE828 00000000A80CE028 119 1 1280 00000000D4F9A130 00000000CEFC4598 00000000A80CE028 119 1 1280 00000000D1FC9E30 00000000A80CEBB8 00000000A80CE028 119 1 1280 00000000D8F84740 00000000D1FC9E30 00000000A80CE028 119 1 1280 00000000A80CEBB8 00000000D4F9A130 00000000A80CE028 378 1 25756 00000000A80CEA38 00000000A80CEA38 00000000A80CE028 385 1 21575 00000000A80CE878 00000000A80CE878 00000000A80CE028 568 1 3864 00000000D9F57B78 00000000D2FC53A8 00000000A80CE028 568 1 3864 00000000D5F995F0 00000000CFFC4700 00000000A80CE028 568 1 3864 00000000D2FC53A8 00000000A80CE8E8 00000000A80CE028 568 1 3864 00000000A80CE8E8 00000000D5F995F0 00000000A80CE028 720 1 115908 00000000A80CECC8 00000000A80CECC8 00000000A80CE028 780 1 14810 00000000E4FB9CD8 00000000A80CE998 00000000A80CE028 20324 1 47648 00000000D0FDF550 00000000A80CEB98 00000000A80CE028 20324 1 47648 00000000D3FAFB20 00000000CDFB50E8 00000000A80CE028 20324 1 47648 00000000D6FEF6A8 00000000D0FDF550 00000000A80CE028 20324 1 47648 00000000A80CEB98 00000000D3FAFB20 00000000A80CE028 73154 3 64962 00000000A80CEBC8 00000000A80CEBC8 00000000A80CE028 73610 3 78492 00000000A80CE998 00000000D6F864C8 00000000A80CE028 74505 3 173812 00000000A80CE678 00000000A80CE678 00000000A80CE028 74952 3 254615 00000000A80CECE8 00000000A80CECE8 00000000A80CE028 74978 3 253018 00000000A80CE848 00000000A80CE848 00000000A80CE028 75239 3 224361 00000000A80CE808 00000000A80CE808 00000000A80CE028 4294967295 4 1752 00000000A80CEAF8 00000000A80CEAF8 25 rows selected.
热点块竞争与解决
SQL> SELECT * FROM (SELECT addr, child#, gets, misses, sleeps, immediate_gets igets, immediate_misses imiss, spin_gets sgets FROM v$latch_children WHERE NAME = \'cache buffers chains\' ORDER BY sleeps DESC) WHERE ROWNUM < 11; 2 ADDR CHILD# GETS MISSES SLEEPS IGETS IMISS SGETS ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 00000000A80F1610 70 6399 12 4 152 0 8 00000000A83ED658 1463 5310 2 2 89 0 0 00000000A829F9C8 853 5439 10 2 129 0 8 00000000A852DF60 2048 4980 0 0 88 0 0 00000000A852DC40 2044 3831 0 0 101 0 0 00000000A852DB78 2043 11789 0 0 87 0 0 00000000A852DAB0 2042 1044 0 0 89 0 0 00000000A852D9E8 2041 5321 0 0 95 0 0 00000000A8529920 2040 2905 0 0 89 0 0 00000000A8529858 2039 1736 0 0 93 0 0 10 rows selected.
SQL> SELECT b.addr, a.ts#, a.dbarfil, a.dbablk, a.tch, b.gets, b.misses, b.sleeps FROM (SELECT * FROM (SELECT addr, ts#, file#, dbarfil, dbablk, tch, hladdr FROM x$bh ORDER BY tch DESC) WHERE ROWNUM < 11) a, (SELECT addr, gets, misses, sleeps FROM v$latch_children WHERE NAME = \'cache buffers chains\') b WHERE a.hladdr = b.addr; ADDR TS# DBARFIL DBABLK TCH GETS MISSES SLEEPS ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 00000000A84DEAF8 0 1 178 218 2282 0 0 00000000A80DFAB8 0 1 183 217 1625 0 0 00000000A8438160 0 1 181 217 2158 0 0 00000000A83D30D8 0 1 176 217 2556 0 0 00000000A8330740 0 1 179 217 2096 0 0 00000000A828DE70 0 1 182 217 2511 0 0 00000000A8228DE8 0 1 177 217 2476 0 0 00000000A8182450 0 1 180 217 3223 0 0 00000000A82BA0D8 2 4 2 187 2560 0 0 00000000A816C2B8 0 1 201 186 38016 2 0 10 rows selected.
SELECT distinct e.owner, e.segment_name, e.segment_type FROM dba_extents e, (SELECT * FROM (SELECT addr, ts#, file#, dbarfil, dbablk, tch FROM x$bh ORDER BY tch DESC) WHERE ROWNUM < 11) b WHERE e.relative_fno = b.dbarfil AND e.block_id <= b.dbablk AND e.block_id + e.blocks > b.dbablk;
SQL> SELECT hash_value,sql_text FROM v$sqltext WHERE (hash_value, address) IN ( SELECT a.hash_value, a.address FROM v$sqltext a, (SELECT DISTINCT a.owner, a.segment_name, a.segment_type FROM dba_extents a, (SELECT dbarfil, dbablk FROM (SELECT dbarfil, dbablk FROM x$bh ORDER BY tch DESC) WHERE ROWNUM < 11) b WHERE a.relative_fno = b.dbarfil AND a.block_id <= b.dbablk AND a.block_id + a.blocks > b.dbablk ) b WHERE upper(a.sql_text) LIKE \'%\' || b.segment_name || \'%\' AND b.segment_type = \'TABLE\') 2 3 4 5 6 7 ORDER BY hash_value, address, piece; HASH_VALUE SQL_TEXT ---------- ---------------------------------------------------------------- 103134026 INSERT INTO "SAPR3"."DBSTATIORA" (TNAME, INAME, ANDAT, VWTYP, IN 103134026 DBL, INDBS, INDRU, INDDE) VALUES (\'TRNL_E071~\', \'TRNL_E071^0\', \' 103134026 20200505171508\', \' \', 0, 0, 0, 0) 104653397 UPDATE "SAPR3"."DBSTATIORA" SET ANDAT = \'20200505171547\', VWTYP 104653397 = \' \', INDBS = 43280, INDRU = 43280 WHERE TNAME = \'DDNTT~\' AND I 104653397 NAME = \'DDNTT~0\'
以上是关于[ORACLE] oracle Buffer Cache 之Hash Bucket与Hash Chain List(cache bufferschain)的主要内容,如果未能解决你的问题,请参考以下文章
Oracle 等待事件之 buffer busy waits
lnux内核的malloc实现(Oracle的cache buffer影子)