Transfer from ------------http://blog.csdn.net/robinson1988/article/details/5982996
Buffer Cache principle
We are monitoring waiting events. When viewing AWR and ASH reports, we often see latch: cache buffers chains, and may also see latch: cache buffers lru chain waiting events. For the waiting event of cache buffers chains, I believe everyone The most troublesome thing is that if you don't have a deep understanding of Buffer Cache, you will be at a loss when encountering these waiting events. The purpose of this article is to explain the principle of Buffer Cache so that everyone can handle these latch contention handily.
Overview of Buffer Cache
Buffer Cache is a part of SGA. Oracle uses Buffer Cache to manage data blocks. The ultimate goal of Buffer Cache is to reduce disk I/O as much as possible. There are three main structures in Buffer Cache to manage Buffer Cache.
Hash Bucket & Hash Chain List: Hash Bucket and Hash Chain List are used to quickly locate data blocks.
LRU List: Mounted with pointers to specific free buffers, pinned buffers, and dirty buffers that have not been moved to the write list. The so-called free buffer refers to a buffer that does not contain any data, and the so-called pinned buffer refers to the buffer that is currently being accessed.
Write(Dirty)List: Mount the information pointing to the specific dirty block. The so-called dirty block refers to a block that has been modified in the buffer cache but has not been written to the disk.
Hash Bucket与Hash Chain List
After oracle calculates all the buffers in the buffer cache through an internal Hash algorithm , these buffers are placed in different Hash Buckets . There is one in every Hash Bucket
Hash Chain List , through this list, connect the blocks in this Bucket together.
Let's take a simple example to introduce the Hash algorithm. Oracle's Hash algorithm is definitely not that simple. Only Oracle knows the specific algorithm.
• A simple mod function, let’s go to mod 4
Ø 1 against 4 = 1
Ø 2 against 4 = 2
Ø 3 against 4 = 3
Ø 4 against 4 = 0
Ø 5 against 4 = 1
Ø 6 against 4 = 2
Ø 7 against 4 = 3
Ø 8 against 4 = 0
……………abridgement…………………..
So here is equivalent to creating 4 Hash Buckets
If there is the following block:
blcok :DBA(1,1) ------> (1+1) mod 4 =2
block :DBA(1,2) ------> (1+2) mod 4 =3
block :DBA(1,3) ------> (1+3) mod 4 =0
block :DBA(1,4) ------> (1+4) mod 4 =1
block :DBA(1,5) ------> (1+5) mod 5 =2
………........abridgement…………………....
For example, if I want to access block(1,5), I will perform a Hash operation on it, and then look for it in the bucket whose Hash Bucket is 2. The bucket whose Hash Bucket is 2 now has 2 blocks.
These two block hanging on Hash Chain List above
How exactly is the Hash Chain List composed? Here we are going to mention the base table x$bh
SQL> desc x$bh
Name Null? Type
----------------------- - ----------------
ADDR RAW(8) ---block address in the buffer cache
INDX NUMBER
INST_ID NUMBER
HLADDR RAW(8) --latch:cache buffers chains 的address
BLSIZ NUMBER
NXT_HASH RAW(8) ---point to the next block of the same Hash Chain List
PRV_HASH RAW(8) ---point to the previous block of the same Hash Chain List
NXT_REPL RAW(8)---point to the next block in the LRU list
PRV_REPL RAW(8)---point to the previous block in the LRU list
………………abridgement…………………………
Hash Chain List is a doubly linked list composed of NXT_HASH and PRV_HASH in x$bh. The schematic diagram is as follows:
Through the two pointers of NXT_HASH and PRV_HASH, the blocks in the same Hash Chain List are connected in series.
Understand Hash Bucket and Hash Chain List , let’s take a look now
Schematic diagram of the structure of Buffer Cache managed by Hash Bucket and Hash Chain List
From the figure, we can see that a latch:cache buffers chains (x$bh.hladdr) can protect multiple Hash Buckets . In other words, if I want to access a block, I must first obtain this latch, a Hash Bucket. Corresponds to a Hash Chain List , and this
One or more Buffer Headers are mounted on the Hash Chain List .
The number of Hash Buckets is affected by the implicit parameter _db_block_hash_buckets,
Latch: The number of cache buffers chains is affected by the implicit parameter _db_block_hash_latches
The hidden parameter can be viewed through the following query:
SQL> select * from v$version;
BANNER
------------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
2 FROM x$ksppi x, x$ksppcv y
3 WHERE x.inst_id = USERENV ('Instance')
4 AND y.inst_id = USERENV ('Instance')
5 AND x.indx = y.indx
6 AND x.ksppinm LIKE '%_db_block_hash%'
7 /
NAME VALUE DESCRIB
------------------------- --------------- --------------------------------------
_db_block_hash_buckets 524288 Number of database block hash buckets
_db_block_hash_latches 16384 Number of database block hash latches
_db_block_hash_buckets This implicit parameter is equal to the next prime number of db_block_buffers/4 before 8i
At 8i, the parameter is equal to db_block_buffers*2,
After 9i, the parameter is a prime number less than and closest to db_block_buffers*2
_db_block_hash_latches This implicit parameter represents the number of cache buffers chains latches . We don’t need to study how it is calculated.
It can be seen that the number of hash buckets has increased by 8 times since 8i .
You can use the following query to calculate the number of cache buffers chains latches
SQL> select count(*) from v$latch_children a,v$latchname b where a.latch#=b.latch# and b.name='cache buffers chains';
COUNT(*)
----------
16384
You can also use the following query to calculate the number of cache buffers chains latches
SQL> select count(distinct hladdr) from x$bh ;
COUNT(DISTINCTHLADDR)
---------------------
16384
According to our query, a cache buffers chains latch will manage 32 Hash Buckets on average , so now we can find a latch at will to verify the structure diagram mentioned earlier.
SQL> select * from (select hladdr,count(*) from x$bh group by hladdr) where rownum<=5;
HLADDR COUNT(*)
---------------- ----------
C000000469F08828 15
C000000469F088F0 14
C000000469F089B8 15
C000000469F08A80 24
C000000469F08B48 17
We query the data block protected by the latch address as C000000469F08828
SQL> select hladdr,obj,dbarfil,dbablk, nxt_hash,prv_hash from x$bh where hladdr='C000000469F08828' order by obj;
HLADDR OBJ DBARFIL DBABLK NXT_HASH PRV_HASH
---------------- ---------- ---------- ---------- ---------------- ----------------
C000000469F08828 2 388 322034 C0000004686ECBD0 C00000017EF8D658
C000000469F08828 2 388 396246 C0000004686ECA60 C0000004686ECA60
C000000469F08828 18 411 674831 C0000004686ECC00 C0000004686ECC00
C000000469F08828 216 411 438948 C0000004686ECBB0 C0000004686ECBB0
C000000469F08828 216 220 100217 C0000004686ECAA0 C0000004686ECAA0
C000000469F08828 216 220 60942 C000000151FB5DD8 C0000004686ECBD0
C000000469F08828 569 411 67655 C00000011FF81668 C0000001E8FB7AC0
C000000469F08828 569 280 1294 C0000004686ECB60 C000000177F9F078
C000000469F08828 58744570 210 332639 C000000177F9F078 C0000004686ECB60
C000000469F08828 65178270 254 408901 C0000004686ECBF0 C0000004686ECBF0
C000000469F08828 65347592 84 615093 C0000004686ECB90 C0000004686ECB90
C000000469F08828 65349200 765 1259399 C0000004686ECA70 C0000004686ECA70
Please observe DBA (388,396246), its NXT_HASH is the same as PRV_HASH, which means that DBA (388,396246) is mounted on a Hash Chain that contains only one data block .
Please also note that when I calculated by count(*), there were 15 blocks, but after the query, it became 12 blocks, which means that 3 blocks were flushed to the disk.
When a user process wants to access Block(569,411):
l Apply the Hash algorithm to the Block to obtain the Hash value.
l Obtain cache buffers chains latch
l Search for the corresponding Buffer Header in the corresponding Hash Bucket
l If you find the corresponding Buffer Header, then judge the status of the Buffer to see if you need to construct a CR Block, or the Buffer is in pin state, and finally read.
l If it cannot be found, it is read from the disk to the Buffer Cache.
Before Oracle9i, if other user processes have already obtained the latch, the new process must wait until the user process is searched (the latch will be released after the search is completed). Beginning with Oracle9i, the cache buffers chains latch can be shared read-only, which means that user process A accesses Block (84,615093) in a read-only (select) manner. At this time, the latch is obtained, and user process B is also read-only Access Block (765, 1259399) in the way, then at this time because it is read-only access, user process B can also get the latch. However, if users want to process B with exclusive access to Block (765,1259399), then the user process B will wait for the user process A releases the latch, this time Oracle user process B will mark a latch: cache buffers chains of Wait for the event.
What should we do if we encounter latch:cache buffers chains ?
l Not optimized SQL. A large number of logically read SQL statements may cause very serious latch:cache buffers chains to wait, because every time you want to access a block, you need to get the latch. Because there are a lot of logical reads, then latch:cache buffers chains are added. Probability of contention.
Ø For the running SQL statement, there is a very serious latch: cache buffers chains contention. You can use the following SQL to view the execution plan and try to optimize the SQL statement.
select * from table(dbms_xplan.display_cursor('sql_id',sql_child_number));
Ø If the SQL has been run, we will look at SQL Statistics->SQL ordered by Gets->Gets per Exec in the AWR report to try to optimize these SQL.
l Hot block contention.
Ø The following query finds out the competing latch addresses of the Top 5.
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<6;
Ø Then use the following query to find out the hot block.
select /*+ RULE */
e.owner ||'.'|| e.segment_name segment_name,
e.extent_id extent#,
x.dbablk - e.block_id + 1 block#,
x.tch, /* sometimes tch=0,we need to see tim */
x.tim ,
l.child#
from
v$latch_children l,
x$bh x,
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 ;
l There are too few hash buckets, and the implicit parameter of _db_block_hash_buckets needs to be changed. In fact, after Oracle9i, we basically won't encounter this problem, unless we encounter a bug. Therefore, this is not recommended. Remember, you must consult Oracle Support before modifying Oracle's implicit parameters.
LRU List与LRU Write List
As mentioned earlier, if a user process finds that a block is not in the Buffer Cache, the user process will read the block from the disk into the Buffer Cache. Before reading the block into the Buffer Cache, first look for the Free buffer on the LRU list. During the search, if the Dirty Buffer is found, it will be moved to the LRU Write List. If the Dirty Queue exceeds the threshold by 25% (as shown in the query below), then DBWn will write the Dirty Buffer to disk.
SQL> select kvittag,kvitval,kvitdsc from x$kvit where kvittag in('kcbldq','kcbfsp');
RECEIPT RECEIPT KVITDSC
-------------------- ---------- -------------------------------------------------------
kcbldq 25 large dirty queue if kcbclw reaches this
kcbfsp 40 Max percentage of LRU list foreground can scan for free
According to the above query, we also know that when a user process scans the LRU list for more than 40% without finding the Free Buffer, then the user process will stop scanning the LRU list at this time, and at the same time notify DBWn to write the Dirty Buffer to disk, and the user process will also A free buffer wait wait event will be recorded. If we often see free buffer wait waiting events, then we should consider increasing the Buffer Cache.
Starting from Oracle8i, LRU List and Dirty List have added auxiliary Lists. Oracle refers to LRU List and LRU Write List collectively as Working Set (WS). Each WS contains several lists with different functions, and each WS will have a Cache Buffers LRU chain Latch protection (the knowledge comes from DSI405). If the database is set with multiple DBWRs, there will be multiple WS in the database. If multiple buffer pools (default, keep, recycle) are enabled in the Buffer Cache, each independent buffer pool will have its own WS. So let's check it below to verify the above theory:
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
2 FROM x$ksppi x, x$ksppcv y
3 WHERE x.inst_id = USERENV ('Instance')
4 AND y.inst_id = USERENV ('Instance')
5 AND x.indx = y.indx
6 AND x.ksppinm LIKE '%db_block_lru_latches%'
7 /
NAME VALUE DESCRIB
------------------------------ ---------- -----------------------------
_db_block_lru_latches 32 number of lru latches
SQL> show parameter db_writer
NAME TYPE VALUE
----------------------------- -------------- ------
db_writer_processes inte 2
SQL> show parameter cpu_count
NAME TYPE VALUE
------------------------------------ -------------------- ------------
cpu_count integer 8
We found that there are 32 Cache Buffers LRU chain Latch. Starting from Oracle9i, _db_block_lru_latches is 4 times the CPU_COUNT. If DB_WITER_PROCESS is less than 4, put DB_WITER_PROCESS greater than four. I don’t know, and I haven’t seen any database parameter with DB_WITER_PROCESS greater than 4. Let's check how many Working Sets there are:
SQL> select count(*) from x$kcbwds;
COUNT(*)
----------
32
We found that there are 32 WS, which does not mean that the database must use these 32 WS. Some WS are pre-allocated by the database, so we don't need to restart the database when we enable Keep pool and recycle pool.
So we only used 4 WS here.
SQL> select count(*) from x$kcbwds where CNUM_REPL>0;
COUNT(*)
----------
4
The X$KCBWDS base table has been queried many times above, now let’s take a look at the main fields of this base table
ADDR RAW(4) ------address
INDX NUMBER
INST_ID NUMBER --------instance number
SET_ID NUMBER --------work set id
DBWR_NUM NUMBER ------DBWR number
BLK_SIZE NUMBER ----------WORKSET的BLOCK SIZE
PROC_GROUP NUMBER
CNUM_SET NUMBER
FLAG NUMBER
CKPT_LATCH RAW(4) CHECKPOINT LATCH
CKPT_LATCH1 RAW(4)
SET_LATCH RAW(4) NEXT REPLACEMENT CHAIN
NXT_REPL RAW(4) PRV REPLACEMENT CHAIN
PRV_REPL RAW(4) REPLACEMENT AUX CHAIN
NXT_REPLAX RAW(4)
PRV_REPLAX RAW(4)
Number of BLOCKs on CNUM_REPL NUMBER REPLACEMENT CHIAN
ANUM_REPL NUMBER Number of BLOCKs on AUX CHAIN
COLD_HD RAW(4) Address of COLD HEAD
The maximum number of BUFFER at HBMAX NUMBER HOT
The current number of BUFFER on the HBUFS NUMBER HOT end
NXT_WRITE RAW(4) LRU-W链
PRV_WRITE RAW(4) LRU-W链
NXT_WRITEAX RAW(4) LRU-W AUX链
PRV_WRITEAX RAW(4) LRU-W AUX链
CNUM_WRITE NUMBER LRU-W的BUFFER数
ANUM_WRITE NUMBER LRU-W AUX BUFFER number
NXT_XOBJ RAW(4) REUSE OBJ chain (used when TRUNCATE, DROP, etc. operations)
PRV_XOBJ RAW(4) REUSE OBJ链
NXT_XOBJAX RAW(4) REUSE OBJ AUX链
PRV_XOBJAX RAW(4)
CNUM_XOBJ NUMBER
ANUM_XOBJ NUMBER
NXT_XRNG RAW(4) reuse range chain (used in TABLESPACE OFFLINE and other operations)
PRV_XRNG RAW(4)
NXT_XRNGAX RAW(4) REUSE RANGE AUX链
PRV_XRNGAX RAW(4)
Please pay attention to the red field. It is precisely because of the red field and the NXT_REPL and PRV_REPL fields in x$bh mentioned earlier that the LRU List and LRU Write List are formed.
The figure below is a schematic diagram of the structure of the LRU List
So what is the purpose of adding these AUX Lists? After the database is started, the Buffer is first stored on the LRU AUX List, and the user process searching for Free Buffer will proceed from the end/cold end of the LRU AUX List. When these blocks are modified or when the user process wants to construct a CR block (to construct a CR block also means that this block does not meet the read consistency and is Dirty), the Buffer on the LRU AUX List will be moved to the LRU In the middle of the Main List, remember that the middle is neither the head nor the end, then DBWR can start from the LRU Main List when searching for Dirty Buffer (Note: DBWR searching for the LRU Main List is caused by incremental checkpoints), DBWR is in When searching the LRU Main List, if a cold buffer that can be reused is found, it will be moved to the LRU AUX List, so that the buffers on the LRU Main List are basically Dirty Buffers, which improves the search efficiency. DBWR moves the searched Dirty Buffer to the LRUW Main List. When the Dirty Buffer needs to be written out, it moves the Dirty Buffer to the LRUW AUX List. In this way, when the DBWR needs to write out, it can be written out from the LRUW AUX List. , This is actually an asynchronous writing mechanism. (Knowledge Source Metalink: 157868.1 )
According to the above explanation, when the user process wants to read Block from the disk to the Buffer Cache, it needs to obtain the Cache Buffers LRU chain Latch, or when DBWR scans the LRU Main List, it needs to obtain the Cache Buffers LRU chain Latch.
Therefore, when we find that Cache Buffers LRU chain Latch ranks very high on the AWR report, then we can take the following methods:
l Increase Buffer Cache, too small Buffer Cache will cause a lot of disk I/O, which will inevitably lead to
Cache Buffers LRU chain Latch competition.
l Optimize SQL with a large number of full table scans and high disk I/O. If SQL efficiency is very low, a large number of full table scans, or scans without selective indexes will cause this problem.
l Use multi-buffer pool technology to keep the Hot Segments. The information of Hot Segments can be obtained from the Segment Statistics in the AWR report.
Regarding Buffer Cache, we can only stop here, we can't go further, the information is too small and messy.