Sei sulla pagina 1di 8

Introduction

This article describes what issues affect the performance of the buffer cache and DBWR
(database writer) in Oracle releases 7.1 to 9.2 inclusive. The notes here are particularly important
if your system shows any of the following:

Latch contention for the 'cache buffers lru chain' or the "cache buffer chain" latch

Large "Average Write Queue" length

Lots of time spent waiting for "write complete waits"

Lots of time spent waiting for "free buffer waits" or "Buffer busy waits"

What is the buffer cache ?


Oracle keeps copies of database blocks in an area of the SGA known as the buffer cache. The
cache may hold more than one copy of a block from different points in time, and may contain
'dirty' blocks - ie: blocks which have been updated but not yet flushed back to disk. The database
writer/s (DBWR or DBWn processes) are responsible for writing dirty blocks to disk while any
user session can read blocks into the cache.
All blocks in the buffer cache are on an LRU (least recently used) list - when a process needs a
free buffer it scans from the LRU end of this list for a non-dirty buffer that it can use. The 'cache
buffers lru chain' latch/es serialize operations on the LRU list/s. (In Oracle8i onwards the
algorithm used for the LRU lists is different to earlier releases but the influencing factors remain
the same).
@ See @Note:104937.1 for a description

Evaluating Buffer cache Activity


The buffer cache hit ratio measures how many times a required block was found in memory
rather than having to execute a expensive read operation on disk to get the block.
Querying the V$SYSSTAT view is possible to obtain the statistical information useful for tuning
the buffer cache. To calculate this ratio you must consider the Oracle version your are running
on. It is recommended to have a hit ratio higher than 80% before increasing the buffer cache size.
See Note:33883.1 for a detailed explanation on how to calculate this ratio on each Oracle
version.

Buffer Cache Advisory

In Oracle 9i it is possible to use the "Dynamic Buffer Cache Advisory feature" which enables
and disables statistic gathering for predicting the behaviour of the buffer cache with different
cache sizes. Keep in mind that enabling this feature causes CPU and memory overheads in the
system, hence it is recommended to use it only while the system is being monitored rather than
keeping it enabled permanently.
V$DB_CACHE_ADVICE view is populated when the DB_CACHE_ADVICE parameter is
enabled. This view shows the simulated miss rates for a range of potential buffer cache
sizes.Each cache size simulated has its own row in this view, with the predicted physical I/O
activity that would take place for that size. The DB_CACHE_ADVICE parameter is dynamic, so
the advisory can be enabled and disabled dynamically to allow you to collect advisory data for
specific workloads.
See Note:148511.1 - Oracle9i NF: Dynamic Buffer Cache Advisory, to learn how to configure
and use this feature.

Tuning the Buffer cache:


Tuning the buffer cache is not limited to determining the hit ratio and increasing the
DB_BLOCK_BUFFERS parameter
When tuning the buffer pool, avoid the use of additional buffers that contribute little or nothing
to the cache hit ratio.
A common mistake is to continue increasing the value of DB_BLOCK_BUFFERS. Such
increases have no effect if you are doing full table scans or other operations that do not use the
buffer cache.
Before of doing this, is necessary to determine what latch or wait event is involved to then tune
the database or the application accordingly. (See section "Most common Buffer Cache Waits and
Latches" of this document for further details)
From the point of view of tuning the buffer cache there are 3 main things you can influence:
1. How often blocks are placed in the cache. Each block placed into the cache moves other
blocks down the LRU
2. How quickly DBWR can clear dirty buffers from the cache Especially if the dirty buffers
are causing waits
3. The size of the buffer cache Including the use of multiple buffer pools in Oracle8
In this article we list the things that can influence performance in these three areas.

Input to the cache

The following sections describe things that affect the rate at which buffers in the cache are used.
Execution Plans
By far the biggest factor influencing the rate at which buffers are used are the execution plans of
the SQL statements issued by the application. If a statement performs 10000 block gets rather
than 100 when executing a statement it will not only be slower itself but can affect other users.
Eg: Consider a statement like:
select * from employee where empid=1023 and gender='MALE';

If EMPLOYEE is a large table and this statement always uses the GENDER index rather than
the EMPID index then you scan LOTS of blocks (from the GENDER index) causing them to be
read into the cache (or moved up the LRU if already there). This pushes other blocks, including
dirty blocks, further down the LRU list.
Sorting and Sort Parameters
Sorting within Oracle is described in detail in other articles. Here we focus on the impact on the
buffer cache and DBWR. Sort operations use up to SORT_AREA_SIZE bytes of memory. If a
sort can be performed within this amount of memory and the result set fits within
SORT_AREA_RETAINED_SIZE then there is no need to start writing blocks to disk. If more
sortspace is needed it is then necessary to use a TEMPORARY segment on disk to accommodate
the intermediate sort runs and/or the sort results . There are 2 ways sort blocks can be sent to
disk:
via the buffer cache (and then DBWR)
Using sort direct writes
The first of these is often the default, and in Oracle 7.1 is the only option available. Sort blocks
are placed into the buffer cache thus aging all other blocks. When the sort blocks reach the LRU
end of the least recently used list DBWR will flush them to disk. This can impact the
performance for everyone else as private sort blocks (sort blocks are of no use to anyone else)
can flood DBWR and age blocks in the cache more quickly.
In Oracle 7.2 the parameter SORT_DIRECT_WRITES can be set to cause processes to write sort
blocks direct to disk avoiding the buffer cache. It is generally desirable to set
SORT_DIRECT_WRITES to TRUE to ensure sort blocks do not impact the buffer cache.
Note 1: Setting SORT_DIRECT_WRITES=TRUE causes additional memory to be allocated for
the session.
Note 2: In a lightly loaded environment SORT_DIRECT_WRITES may cause an individual job
to take slightly longer ! Consider that when blocks are placed in the buffer cache it is acting
almost like a memory extension to that process as "GETs" of sort blocks may be satisfied from
the cache rather than from disk.
Since Oracle 8.1 the parameter SORT_DIRECT_WRITES became obsolete and direct writes are
always used for sort operations that do not fit into the sort area size. See Note:135223.1
CACHED Tables and Full Table Scans

It is possible to mark tables within Oracle to be cached using the CACHE option of the CREATE
or ALTER TABLE commands. Provided the table is within CACHE_SIZE_THRESHOLD then
this causes the blocks of full scans of that table to be placed at the MRU (most recently used) end
of the LRU aging other blocks in the cache. Inappropriate caching of tables can thus contribute
to problems with the buffer cache - take care with this option.
The parameter CACHE_SIZE_THRESHOLD is obsoleted in 8.1. In Oracle8i the use of multiple
buffer pools is intended to allow objects to be cached without using this parameter.
In Oracle9i onwards Oracle internally decides whether to cache blocks from table scans in the
buffer cache (or not) based on the cache size and the number of blocks expected to be visited.
More details on this can be read in Note:787373.1.
Data Clustering
Data clustering can affect the number of blocks that queries have to visit to find the result set.
This can be as simple as the PCTFREE and PCTUSED attributes causing fewer rows per block
than is optimal for the application.
A less obvious issue which can affect the IO rates is how well data is clustered physically. Eg:
Assume that you frequently fetch rows from a table where a column is between two values via an
index scan. If there are 100 rows in each index block then the two extremes are:
Each of the table rows is in a different physical block (100 blocks need to be read for each
index block)
The table rows are all located in the few adjacent blocks (a handful of blocks need to be read
for each index block)
Pre-sorting or reorganizing data can help to tackle this in severe situations. Adding an extra
column to an index may eliminate data block access altogether if the queries use this extra
column frequently in their WHERE clause.
Parallel Query
Some operations can be performed much faster using the parallel query features of Oracle7/8/9.
These may benefit the buffer cache as parallel queries can perform direct reads avoiding the
buffer cache - ie: They can read direct from disk into private process memory. Nb: This only
occurs for certain access paths in a query.

Increase DBWR throughput


DBWR throughput is very platform and version specific so only general observations can be
made here. The following items may influence the rate at which DBWR can clear blocks from
the cache:
Physical disk attributes (stripe size, speed, layout etc..)
Raw devices versus File System Files
Spreading written data across more disks/files

Using Asynchronous writes where available


Using multiple database writers where asynch. IO is not available. DB_WRITERS in
Oracle7, DBWR_IO_SLAVES in Oracle8/9.
Using multiple DB Writer gatherer processes in Oracle8 DB_WRITER_PROCESSES
Setting _DB_BLOCK_WRITE_BATCH to a large number. This parameter is obsoleted in
8.1.
Using the "Multiple buffer pools" feature in Oracle8 and Higher. See Note:135223.1
Note that there many port specific issues which affect the optimal setup for DBWR on a given
platform. These range from choosing a DB_BLOCK_SIZE which is a multiple of the page size
used by the operating system for IO operations to configuring Asynchronous IO correctly.

Buffer Cache Size and Configuration


Other things that affect the performance of the buffer cache include:
o DB_BLOCK_BUFFERS is the actual size of the buffer cache itself. Be careful
when changing the size of the buffer cache as it affects memory requirements and
may also affect whether a table is classed as a small table or a large table for
caching during full table scans (small tables are placed at the MRU end of the
LRU).
o In 9i, the parameter DB_CACHE_SIZE specifies the size of the DEFAULT buffer
pool for buffers with the primary block size. 9i allows to configure buffer caches
of different block size. DB_nK_CACHE_SIZE specifies the size of the cache for the
nK buffers. The value of nk should be other than DB_BLOCK_SIZE.
o DB_BLOCK_LRU_LATCHES allows multiple LRU chains in the buffer cache
from Oracle 7.3 onwards. This generally defaults to a sensible value but can be set
explicitly in the init.ora file. On Oracle7 DB_BLOCK_LRU_LATCHES should
be set to 2 * number of CPU's. On Oracle8 set it to 2 * number of CPU's *
number of Buffer Pools configured.
o In Oracle8 it is possible to have up to 3 separate buffer caches. This is described
in the standard documentation and is configured at object level using the
BUFFER_POOL storage attribute.
o DB_BLOCK_LRU_STATISTICS should not be set to TRUE
o In Oracle9 this parameter cannot be manually set anymore (not even using
_DB_BLOCK_LRU_STATISTICS). It is now hard coded to be 1/2
CPU_COUNT for each buffer cache (DEFAULT, KEEP, RECYCLE, and nK
caches).

Most common Buffer Cache Waits and Latches

Latches:
Please refers to Note:22908.1 for a complete discussion on detecting and resolving latch
contention.

Cache buffer chain latch:


This latch is acquired when searching for data blocks cached in the SGA. Since the
Buffer cache is a chain of blocks, each of this chains is protected by a child of this latch
when needs to be scanned. Contention in this latch can be caused by very heavy access to
a single block. This would require the application to be reviewed. As of Oracle8i there are
many hash buckets to each latch and so there will be lots of buffers under each latch.

Cache buffers LRU chain latch:


Processes need to get this latch when they need to move buffers based on the LRU block
replacement policy in the buffer cache. Contention in this latch can be avoided
implementing multiple buffer pools or increasing the number of LRU latches with the
parameter DB_BLOCK_LRU_LATCHES (The default value is generally sufficient for
most systems). SQL tuning can affect this as well by reducing data blocks visited by a
query.
The behavior of this latch can be affected when extended statistics are enabled using the
parameters DB_BLOCK_LRU_EXTENDED_STATISTICS and
DB_BLOCK_LRU_STATISTICS (These parameters were removed in Oracle8i)

Wait events:

Buffer busy wait:


This event is commonly caused when multiple session are trying to read the same block
or multiple session waiting for a change to complete in the same block. Block contention
corrective actions depends on the type of block involved. Query on V$WAITSTAT and
X$KCBFWAIT to detect the hottest blocks breaking down by the type of block. To
reduce buffer busy waits on:
data blocks:

Reduce number of rows per block whether changing pctfree/pctused or


reducing the DB_BLOCK_SIZE.

Check for 'right-hand-indexes' (indexes that get inserted into at the same
point by many processes). You can use reverse key indexes to distribute
the different information.

See Note:155971.1 for a detailed case-study on how to diagnose and resolve


intensive random access performance problems.
segment header:

Use freelists or increase of number of freelists.

Extent size too small can cause contention on the header when the table
grows regularly. Consider increasing the extent size for the table.

undo header:

Add more rollback segments to reduce the number of transaction per


rollback segment.

Reduce the value of the parameter


TRANSACTION_PER_ROLLBACK_SEGMENT

undo block:

Consider making rollback segments larger in exclusive mode

Free buffer wait:


This will mostly occur because of DBWR not writing out buffers fast enough. Please
refers to the section "Increase DBWR throughput" to improve the speed of this process.

Oracle Bugs
The first diagnostic step to resolve this behavior is to apply the latest patchset available in your
platform. Most of the buffer cache issues related to BUGs can be avoided by applying these
patchsets. The following table summarize the most common BUGs related to buffer cache
problems, possible workarounds and the patchset that fixes the problem.

BUG
Description
Bug:207952 free buffer waits / LRU latch contention

Workaround
Fixed
Not
8174, 9013, 9201

6
possible on write intensive systems.
available
Bug:196736 Increased index block gets / "cache buffer Not
3
chains" contention in 8i/9i.
available
If you shrink a buffer pool by a certain
Bug:226809 amount and later try to grow the shared
Not
8
pool by the same amount and the grow mayavailable
fail with an "insufficient memory" error.

8173, 9013, 9201


9014, 9201