Database Buffer Cache



Hi, in this post, i´m going to explain how to tune Oracle database buffer cache.

It is a SGA memory portion that holds some data blocks, is usually the largest structure within the SGA. All SGA are shared with all database users, so if any user needs any data holds in buffer cache he can read them directly instead of reading disk.

The goal is to minimize the number of reads that an instance needs to perform from disks.. Blocks in database buffer cache works with LRU (Least Recently Used) algorithm which means, that blocks most used will be in memory, and least used will get out.

Of course, if you are using automatic memory management (AMM) you don´t need to set it because this Oracle feature does it for you.



When a oracle server process need some block, it first searches in the Buffer cache, if this block was not find in buffer cache server process get it from disk and load it into buffer cache as MRU (Most Recently Used)... Every time any server process fails to find a block in buffer cache is called a "cache miss" and bring down buffer cache hint ratio. Definitely, we want to maintain this cache above 90%.


The LRU Algorithm and Full Table Scans

When a user process is doing a full table scan, it reads the blocks of the table into buffers and puts them into end of the queue to be the first block to leave (instead of the MRU end). This is because a fully scanned table is probably used only this time and it will full the cache, so the blocks should be moved out quickly to leave more frequently used blocks in the cache. (Unless you do a ALTER TABLE CACHE; of this table)
Obviously full table scans will decrease buffer cache hit ratio....

Size of the database buffer cache

A standard block size is defined in DB_BLOCK_SIZE initialization parameter. DB_CACHE_SIZE parameter defines database buffer cache size for all Tablespaces whom block setup is as default, but if you have a tablespace defined with a block size different you should to define a specific parameter for this tablespace (for exemple for a tablespace with a 8k block you should define DB_8K_CACHE_SIZE parameter)

To see tablespace blocks size:

SQL> select TABLESPACE_NAME, BLOCK_SIZE from dba_tablespaces;

TABLESPACE_NAME                BLOCK_SIZE
------------------------------ ----------
SYSTEM                               8192
SYSAUX                               8192
UNDOTBS1                             8192
TEMP                                 8192
USERS                                8192
WCPVM_IAS_OPSS                       8192
WCPVM_IAS_PORTLET                    8192
WCPVM_IAS_WEBCENTER                  8192
WCPVM_IAS_DISCUSS                    8192
WCPVM_STB                            8192
WCPVM_IAS_TEMP                       8192
WCPVM_IAU                            8192
WCPVM_MDS                            8192
WCPVM_OCS                            8192
WCPVM_OCS_TEMP                       8192
WCPVM_IAS_ACTIVITY                   8192




SQL> show parameter DB_BLOCK_SIZE

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_size                        integer     8192


With this query we can see Cache hist Ratio, as we say if it is below 90% it means a bad database performace...

SET PAGESIZE 60
SET LINESIZE 300

SELECT ROUND((1-(phy.value / (cur.value + con.value)))*100,2) "Cache Hit Ratio"
FROM v$sysstat cur, 
v$sysstat con,
v$sysstat phy
WHERE cur.name = 'db block gets'
AND con.name = 'consistent gets'
AND phy.name = 'physical reads'
/

SQL> SET PAGESIZE 60
SET LINESIZE 300

SELECT ROUND((1-(phy.value / (cur.value + con.value)))*100,2) "Cache Hit Ratio"
FROM v$sysstat cur,
v$sysstat con,
v$sysstat phy
WHERE cur.name = 'db block gets'
AND con.name = 'consistent gets'
AND phy.name = 'physical reads'
/SQL> SQL> SQL>   2    3    4    5    6    7    8

Cache Hit Ratio
---------------
          95.64


To start using V$DB_CACHE_ADVICE view, we had to check first if db_cache_advice parameter is set to on, this parameter control statistics gathering about database buffer cache used for predicting behavior with different cache sizes...

so:

SQL> set linesize 190
SQL> show parameter db_cache_advice

NAME                                 TYPE                             VALUE
------------------------------------ -------------------------------- ------------------------------
db_cache_advice                      string                           ON

It is on (by default), so we can query V$DB_CACHE_ADVICE..

Below is a graphical representation of this view, as you can see, the more buffer assigned to database buffer cache, the fewer physical reads database needs to do. But keep in mind this is a predicting behavior, not a fact.


SQL> COLUMN size_for_estimate          FORMAT 999,999,999,999 heading 'Cache Size (MB)'
COLUMN buffers_for_estimate       FORMAT 999,999,999 heading 'Buffers'
COLUMN estd_physical_read_factor  FORMAT 999.90 heading 'Estd Phys|Read Factor'
COLUMN estd_physical_reads        FORMAT 99,999,999,999,999,999 heading 'Estd Phys| Reads'

SELECT size_for_estimate, buffers_for_estimate, estd_physical_read_factor,
       estd_physical_reads
  FROM V$DB_CACHE_ADVICE
 WHERE name = 'DEFAULT'
   AND block_size = (SELECT value FROM V$PARAMETER WHERE name = 'db_block_size')
   AND advice_status = 'ON';SQL> SQL> SQL> SQL> SQL>   2    3    4    5    6

                                Estd Phys               Estd Phys
 Cache Size (MB)      Buffers Read Factor                   Reads
---------------- ------------ ----------- -----------------------
              96       11,814        1.07         273,396,597,945
             192       23,628        1.06         271,095,709,267
             288       35,442        1.05         269,215,692,032
             384       47,256        1.05         267,280,304,623
             480       59,070        1.04         266,514,403,094
             576       70,884        1.04         265,790,696,842
             672       82,698        1.04         264,978,550,976
             768       94,512        1.03         263,640,085,415
             864      106,326        1.02         261,485,459,270
             960      118,140        1.01         258,608,405,584
           1,056      129,954        1.00         255,216,224,847   Current Size
           1,152      141,768         .99         251,538,683,240
           1,248      153,582         .97         247,825,490,772
           1,344      165,396         .96         243,908,715,196
           1,440      177,210         .94         240,467,179,931
           1,536      189,024         .93         237,233,733,279
           1,632      200,838         .92         234,643,037,809
           1,728      212,652         .91         232,594,822,480
           1,824      224,466         .90         230,871,812,987
           1,920      236,280         .90         228,872,915,219


When your database hit cache ratio is low, it now always means that you need to increase database buffer cache because some operations launched against database like full table scans (as explained above) or in some big OLTP databases many rows are accessed only once, it has no sense to resize this buffer...
To query how many blocks from witch objects are allocated just now in our database buffer cache
set linesize 190
COLUMN object_name FORMAT A40
COLUMN number_of_blocks FORMAT 999,999,999,999

SELECT  o.object_name, o.OBJECT_TYPE, COUNT(*) number_of_blocks  FROM DBA_OBJECTS o, V$BH bh  WHERE o.data_object_id = bh.OBJD  AND o.owner != 'SYS'  GROUP BY o.object_Name,  o.OBJECT_TYPE  ORDER BY COUNT(*);

This are top 6 objects allocated in my buffer cache:
SQL> set linesize 190
COLUMN object_name FORMAT A40
COLUMN number_of_blocks FORMAT 999,999,999,999

SELECT  o.object_name, o.OBJECT_TYPE, COUNT(*) number_of_blocks  FROM DBA_OBJECTS o, V$BH bh  WHERE o.data_object_id = bh.OBJD  AND o.owner != 'SYS'  GROUP BY o.object_Name,  o.OBJECT_TYPE  ORDER BY COUNT(*);
.....................................................................................
.....................................................................................
OBJECT_NAME                              OBJECT_TYPE             NUMBER_OF_BLOCKS
---------------------------------------- ----------------------- ----------------
IDX_ATTR_NAME                            INDEX                              1,147
JPS_ATTRS                                TABLE                              1,428
MDS_ATTRIBUTES_U2                        INDEX                              1,942
MDS_ATTRIBUTES                           TABLE                              2,039

so these are queries selecting last table in the list (MDS_ATTRIBUTES)

SQL> select SQL_ID, SQL_TEXT, COMMAND_TYPE from dba_hist_sqltext where SQL_TEXT like '%MDS_ATTRIBUTES%';

SQL_ID        SQL_TEXT                                                                         COMMAND_TYPE
------------- -------------------------------------------------------------------------------- ------------
fy1zcagmykq67 select PATH.PATH_FULLNAME, PATH.PATH_TYPE, PATH.PATH_GUID, PATH.PATH_DOC_ELEM_NS            3
fb438drcnt9k5 select PATH_FULLNAME, PATH_DOC_ELEM_NSURI, PATH_DOC_ELEM_NAME, PATH_GUID, NS_URI            3
auafcz7927n4v SELECT COMP_SEQ, COMP_LEVEL, COMP_PREFIX, COMP_LOCALNAME, COMP_VALUE, ATT_PREFIX            3
2wn4tjx3g9qfz insert into MDS_ATTRIBUTES(ATT_CONTENTID,ATT_COMP_SEQ,ATT_SEQ,ATT_NSID,ATT_PREFI            2
g0av44hq62ny8 DELETE  /*+  LEADING(MDS_PATHS)  */  FROM MDS_ATTRIBUTES WHERE  EXISTS (SELECT              7
9pbfu1dn18r0y select PATH_FULLNAME, PATH_DOC_ELEM_NSURI, PATH_DOC_ELEM_NAME, PATH_GUID, NS_URI            3
b6czxm1v4g8v4 select PATH_FULLNAME, PATH_DOC_ELEM_NSURI, PATH_DOC_ELEM_NAME, PATH_GUID, NS_URI            3


So, at this point you can try to optimize them by Active session query performance or to resize the buffer cache by:

alter system set db_cache_size = [cache_size]M scope=both sid='*';
or if any of your tablespaces has a different BLOCK_SIZE check hit ratio for avery buffer this way:
SELECT name, physical_reads, db_block_gets, consistent_gets,
       1 - (physical_reads / (db_block_gets + consistent_gets)) "Hit Ratio"
  FROM V$BUFFER_POOL_STATISTICS;
alter system set db_cache_size = [cache_size]M scope=both sid='*';

Comments

Popular posts from this blog

Oracle Historical Session Information with ASH >10g

Check sessions and processes limits in Oracle

Purging and archiving Oracle alert.log and listener.log