buffer busy waits
This wait happens when a session wants to access a database block in the buffer cache but it cannot as the buffer is "busy". The two main cases where this can occur are:
- Another session is reading the block into the buffer (and the session is waiting for that read to complete)
- Another session holds the buffer in an incompatible mode to our request (that is, some other session is changing the buffer).
Wait Time:
Normal wait time is 1 second. If the session was waiting for a buffer during the last wait, then the next wait will be 3 seconds.
| Parameter | Description |
|---|---|
| file# | This is the file number of the data file that contains the block that Oracle needs to wait for. To find the name of this file enter:
select * from v$datafile where file# = file#; |
| block# | This is the block number of the block that Oracle needs to wait for. The block number is relative to the start of the file. To find the object that this block belongs to enter:
select name, kind from ext_to_obj_view where file# = file# and lowb <= block# and highb >= block#; |
| Id | The buffer busy wait event is called from different places in the Oracle kernel based on the type of the block and operation. Each place in the kernel points to different reason. The p3 values are known as reason codes and they are dependent on the version of Oracle. |
|
Reason Code (Id) |
Reason | ||
|---|---|---|---|
|
<=8.0.6 |
8.1.6-9.2 |
>=10.1 |
|
|
0 |
0 |
n/a |
A block is being read |
|
1003 |
100 |
n/a |
We want to NEW the block but the block is currently being read by another session (most likely for undo). |
|
1007 |
200 |
n/a |
We want to NEW the block but someone else has is using the current copy so we have to wait for them to finish. |
|
1010 |
230 |
n/a |
Trying to get a buffer in CR/CRX mode , but a modification has started on the buffer that has not yet been completed. |
|
1012 |
- |
n/a |
A modification is happening on a SCUR or XCUR buffer, but has not yet completed |
|
1012 (dup.) |
231 |
n/a |
CR/CRX scan found the CURRENT block, but a modification has started on the buffer that has not yet been completed. |
|
1013 |
130 |
n/a |
Block is being read by another session and no other suitable block image was found e.g. CR version, so we wait until the read is completed. This may also occur after a buffer cache assumed deadlock. The kernel can't get a buffer in a certain amount of time and assumes a deadlock. Therefore it will read the CR version of the block. This should not have a negative impact on performance, and basically replaces a read from disk with a wait for another process to read it from disk, as the block needs to be read one way or another. |
|
1014 |
110 |
n/a |
We want the CURRENT block either shared or exclusive but the Block is being read into cache by another session, so we have to wait until their read() is completed. |
|
1014 (duplicate) |
120 |
n/a |
We want to get the block in current mode but someone else is currently reading it into the cache. Wait for them to complete the read. This occurs during buffer lookup. |
|
1016 |
210 |
n/a |
The session wants the block in SCUR or XCUR mode. If this is a buffer exchange or the session is in discrete TX mode, the session waits for the first time and the second time escalates the block as a deadlock and so does not show up as waiting very long. In this case the statistic: "exchange deadlocks" is incremented and we yield the CPU for the "buffer deadlock" wait event. |
|
1016 (duplicate) |
220 |
n/a |
During buffer lookup for a CURRENT copy of a buffer we have found the buffer but someone holds it in an incompatible mode so we have to wait. |
Finding Blockers:
Finding the blocking process can be quite difficult as the information required is not externalized. If P3 parameter value (which is reason code) shows that the "buffer busy wait" is waiting for a block read to complete then the blocking session is likely to be waiting on an IO wait (eg: "db file sequential read" or "db file scattered read") for the same file# and block#.
If the wait is due to the buffer being held in an incompatible mode then it should be freed very soon. If not then it is advisable to contact Oracle Support and get 3 SYSTEMSTATE dumps at one minute intervals as the blocking session may be spinning. (Look for ACTIVE sessions with high CPU utilization).
Systemwide Waits:
If the TIME spent waiting for buffers is significant then it is best to determine which segment/s is/are suffering from contention. The "Buffer busy wait statistics" section of the Bstat/estat or STATSPACK reports shows which block type/s are seeing the most contention. This information is derived from the view V$WAITSTAT which can be queried in isolation:
SELECT time, count, class FROM V$WAITSTAT ORDER BY time,count ;
This shows the class of block with the most waits at the BOTTOM of the list. Oracle Support may also request that the following query be run to show where the block is held from when a wait occurs:
SELECT kcbwhdes, why0+why1+why2 "Gets", "OTHER_WAIT" FROM x$kcbsw s, x$kcbwh w WHERE s.indx=w.indx and s."OTHER_WAIT">0 ORDER BY 3
Note: "OTHER_WAIT" is "OTHER WAIT" in Oracle8i (a space rather than an underscore) The following table lists the most commonly seen buffer busy waits and the operations/functions causing the buffer busy waits.
|
Module |
Operation |
|---|---|
|
kdifbk |
Fetches the single index row matching the argument key |
|
kdusru |
Updating the single row piece |
|
kdifind |
Find the appropriate index block to store the key |
|
kdstgr |
Full Tablescan Get row. Rows are accessed by a full table scan. Check the number of FULL tablescans |
|
kdsgrp |
Get Row Piece. Typically row pieces are fected only in case of chained and Migrated Rows. Row chaining has to be analyed and fixed. |
|
kdiixs |
Index Range Scan |
|
kdifxs |
Fetching the next or previous row in the index scan |
|
kdifbk |
Fetches the single index row matching the agreement key |
|
ktugct |
Block cleanout. |
Additional information regarding which files contain the blocks being waited for can be obtained from the internal view X$KCBFWAIT:
SELECT count, file#, name FROM x$kcbfwait, v$datafile WHERE indx + 1 = file# ORDER BY count ;
This shows the file(s) with the most waits (at the BOTTOM of the list). By combining the above information we know what block type(s) in which file(s) are causing waits. The segments in each file can be seen using a query such as:
SELECT distinct owner, segment_name, segment_type FROM dba_extents WHERE file_id= &FILE_ID ;
If there are a large number of segments of the type listed then monitoring V$SESSION_WAIT may help isolate which object is causing the waits.
For example, repeatedly run the following statement and collect the output. After a period of time sort the results to see which file & blocks are showing contention:
SELECT p1 "File", p2 "Block", p3 "Reason" FROM v$session_wait WHERE event='buffer busy waits' ;
Note: In the above query there is no reference to WAIT_TIME as we are not interested in whether a session is currently waiting or not, just what buffers are causing waits.
If a particular block or range of blocks keeps showing waits you can try to isolate the object.
Reducing Waits / Wait times:
As buffer busy waits are due to contention for particular blocks then you cannot take any action until you know which blocks are being competed for and why. Eliminating the cause of the contention is the best option. Note that "buffer busy waits" for data blocks are often due to several processes repeatedly reading the same blocks (eg: if lots of people scan the same index) - the first session processes the blocks that are in the buffer cache quickly but then a block has to be read from disk - the other sessions (scanning the same index) quickly 'catch up' and want the block which is currently being read from disk - they wait for the buffer as someone is already reading the block in.
The following hints may be useful for particular types of contention - these are things that MAY reduce contention for particular situations:
|
Block Type |
Possible Actions |
|---|---|
|
data blocks |
Eliminate HOT blocks from the application. Check for repeatedly scanned / unselective indexes. Change PCTFREE and/or PCTUSED. Check for 'right- hand-indexes' (indexes that get inserted into at the same point by many processes). Increase INITRANS. Reduce the number of rows per block. |
|
segment header |
Increase of number of FREELISTs. Use FREELIST GROUPs (even in single instance this can make a difference). |
|
Freelist blocks |
Add more FREELISTS. In case of Parallel Server make sure that each instance has its own FREELIST GROUP(s). |
|
undo header |
Add more rollback segments. |
The following statistics are related to buffer cache and can be used to investigate the buffer busy waits related issues.
- db_block_gets
- consistent_gets
- physical_reads
- physical_writes
- write_requests
- summed_dirty_queue_length
- db_block_changes
- change_write_time
- consistent_changes
- redo_synch_writes
- redo_synch_time
- exchange_deadlocks
- free_buffer_requested
- dirty_buffers_inspected
- free_buffer_inspected
- DBWR_timeouts
- DBWR_make_free_requests
- DBWR_free_buffers_found
- DBWR_lru_scans
- DBWR_summed_scan_depth
- DBWR_buffers_scanned
- DBWR_checkpoints
- DBWR_flush_block-range
- DBWR_cross_instance_writes
- remote_instance_undo_writes
- remote_instance_undo_requests
- cross_instance_CR_read
- recovery_blocks_read
- recovery_array_reads
- recovery_array_read_time
- CR_blocks_created
- Current_blocks_converted_for_CR