Organization of buffer cache

The organization of buffer cache:

1、LRU与Dirty List

In Buffer Cache, Oracle manages memory through several linked lists.
The LRU list is used to maintain the Buffer in the memory and is managed according to the LRU algorithm. When the database is initialized, all buffers are hashed to the LRU list for management.
When it is necessary to read data from a data file, it is first necessary to search for a Free Buffer on the LRU List, and then read the data into the Buffer Cache; when the data
is modified, the state becomes Dirty, and it can be moved to the Dirty List. All the Buffers on the Dirty List are candidate Buffers that can be written out to data files by DBWR.
A Buffer exists either on the LRU List or on the Dirty List, and cannot exist in multiple lists at the same time.

Cache Buffers Lru Chain Latch Competition and Resolution
When a process needs to read data to Buffer Cache, or when Cache Buffer is managed according to the LRU algorithm, it is inevitable to scan the LRU List
to obtain the available Buffer or change the Buffer status. Oracle's Buffer Cache is a shared memory that can be accessed concurrently by many concurrent processes,
so it is necessary to obtain Latch during the search process (Latch is a serial lock mechanism of Oracle, used to protect the shared memory structure),
lock the memory structure, and prevent concurrency Access to data in corrupted memory.
The Latch used to lock the LRU is the commonly seen Cache Buffers Lru Chain:

SQL> select addr,latch#,name,gets,misses,immediate_gets,immediate_misses
     from v$latch where name='cache buffers lru chain'; 
     
Cache Buffers Lru Chain Latch has multiple sub-Latches, the number of which is controlled by the implicit parameter _db_block_lru_latches .

You can view the current usage of each sub-Latch from the v$latch_children view:

SQL> select addr,child#,name,gets,misses,immediate_gets,immediate_misses
     from v$latch_children where name='cache buffers lru chain';     
    
2、Hash Bucket和Cache Buffer Chain

Oracle introduces the Bucket data structure. Oracle stores all the Buffers managed by an internal Hash algorithm into different Hash Buckets. After being
divided by Hash Buckets, many Buffers are distributed to a certain number of Buckets. , when the user needs to locate whether the data exists in the Buffer, he
only needs to obtain the Hash value through the same algorithm, and then find a small amount of Buffer in the corresponding Bucket to determine.
Internally, the Bucket uses the Cache Buffer Chain (the Cache Buffer Chain is a doubly linked list) to link all Buffers through the Buffer Header information.
The Buffer Header stores the summary information of the corresponding data block, including the file number, block address, status, etc. of the data block. To determine whether the data block exists in the Buffer,
check the Buffer Header to determine.
Corresponding to each Bucket, there is only one Chain. When the user tries to search the Cache Buffer Chain, he must first obtain the Cache Buffer Chain Latch. 

① Starting from Oracle 8i, the number of Buckets has increased greatly; the number of Buffers on each Bucket has been greatly reduced through the increased "dilution" of Buckets.
②Before Oracle 8i, the number of _db_block_hash_latches was consistent with the number of Buckets, and each Latch managed one Bucket;
starting from Oracle 8i, each Latch needs to manage multiple Buckets, because the number of Buffers on each Bucket is greatly reduced, so Latch performance is improved instead.
③There is a Cache Buffer Chain for each Bucket.
④ There is a pointer to a specific Buffer on the Buffer Header

If you want to access the buffer header in the bucket bucket, you must first obtain the cache buffer chain latch. When there are too many data blocks to access, there will be
contention for the cache buffer chain latch.
cache buffer chain latch ----> bucket ------> buffer header -----> buffer cache

The number of cache buffer chain latches is controlled by the hidden parameter __db_block_hash_latches
The number of buckets is controlled by the hidden parameter _db_block_hash_buckets

Buffer Header data can be obtained from the dictionary table of the database. This dictionary table is X$BH. Each Buffer has a record in X$BH.
select count(*) from X$BH;


Summarize:

There are two ways to organize buffer cache: (these two ways are independent)
one is hash buckets/chains way, the purpose of this way is to find specific cached data block (specific cache block)
another way LRU The linked list method is to find an empty block (find any free buffer)

Through the LRU list, the available Buffer is found when physically reading or constructing a CR block.
The latch of the bucket is to locate the Buffer Header during logical reading.
That is to say, in the normal buffer operation, it is basically through the bucket method, and only LRU is used when physically reading.

The number of cache buffer chain latches is controlled by the hidden parameter __db_block_hash_latches.
The number of buckets is controlled by the hidden parameter _db_block_hash_buckets.
Buffer Header data can be queried from the dictionary table of the database. This dictionary table is X$BH. Each Buffer has a record in X$BH.
select count(*) from X$BH;
Cache Buffers Lru Chain Latch has multiple sub-Latches, the number of which is controlled by the implicit parameter _db_block_lru_latches.

Solve the LRU LATCH problem:
 
If the Latch competition is fierce, usually the following methods can be adopted:
appropriately increase the Buffer Cache, which can reduce the chance of reading data to the Buffer Cache and reduce the competition for scanning the LRU List;
the number of LRU Latch can be appropriately increased, and the modification _db_block_lru_latches parameter, this method is not recommended;
through multi-buffer pool technology, you can reduce the impact of undesired data aging and full table scan operations on the Default pool, thereby reducing competition.

Solve the problem of cache buffer chain latch competition

There is an important field TCH in X$BH. TCH is the abbreviation of Touch, which indicates the number of visits to a Buffer. The more times a Buffer is visited, the more "sought after" the Buffer is, and there may be hot block competition.

1. Optimization of hotspot blocks (check and access more blocks through X$BH)
You can get the busiest Buffer in the current database through the following query
SQL>
select *
from (select addr,ts#,file#,dbarfil,dbablk,tch from
x $bh order by tch desc)
where rownum<11;

Combined with the information in dba_extents, you can query which objects these hot buffers come from:
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+e.blocks>b.dbablk;

For the situation where the sid is already known, query the hotspot objects by yourself
 SELECT OBJ, OBJECT_NAME, TCH, TIM
FROM X$BH A, DBA_OBJECTS B
WHERE HLADDR IN (SELECT P1RAW FROM V$SESSION_WAIT WHERE SID = 627)
AND A.OBJ = B.DATA_OBJECT_ID ;

To solve the problem of hotspot blocks, you can disperse the rows in the hotspot block into multiple data blocks,
so that the original hotspot block becomes multiple data blocks, so that the probability of being hashed to the same latch is reduced. .
If the hotspot block belongs to a table, you can export the table data first, then increase the pctfree value of the table, and finally import the data again.
If the hotspot block belongs to the index, you can rebuild the index after setting a higher pctfree parameter. Note that this increases the height of the index.

2. Inadequately optimized SQL statements are the main cause of cache buffers chains latch.
If the SQL statement needs to access too many memory data blocks, it will inevitably hold the latch for a long time. Find out the SQL statements with particularly large logical reads and adjust them.
Find cache buffers chains latch competing sql statement
select /*+rule*/ 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') 
order by hash_value,address,piece;      

おすすめ

転載: blog.csdn.net/2301_76957510/article/details/129852207
おすすめ