oracle buffer cache

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.

Guess you like

Origin blog.csdn.net/songyundong1993/article/details/77575516