DB_CACHE_SIZE - Size Oracle Buffer Cache for I/O Performance
DB_CACHE_SIZE
Section titled “DB_CACHE_SIZE”Overview
Section titled “Overview”DB_CACHE_SIZE specifies the size of the default buffer pool — the SGA region where Oracle caches data blocks read from datafiles. A larger buffer cache means more blocks remain in memory across SQL executions, reducing costly physical I/O and improving query response times. When SGA_TARGET or MEMORY_TARGET is set, Oracle auto-tunes this component through ASMM or AMM and DB_CACHE_SIZE acts as a guaranteed minimum. When auto-management is off, it directly controls the buffer cache size.
The buffer cache is typically the largest SGA component and the highest-leverage tuning target for read-intensive workloads. Even modest increases in the cache hit ratio can eliminate orders of magnitude more physical I/O.
Parameter Type: Dynamic (ALTER SYSTEM)
Default Value: 0 when SGA_TARGET > 0 (Oracle auto-sizes); otherwise a platform-dependent minimum
Valid Range: 0 (auto) or at least DB_BLOCK_SIZE × minimum granule size
Available Since: Oracle Database 9i (renamed from DB_BLOCK_BUFFERS × DB_BLOCK_SIZE)
Modifiable: Yes — ALTER SYSTEM (increase is online; decrease may fail if blocks are pinned)
PDB Modifiable: No — SGA parameters are CDB-level only
Configuration
Section titled “Configuration”Viewing Current Value
Section titled “Viewing Current Value”-- Check DB_CACHE_SIZE parameter valueSELECT name, value AS bytes, value / (1024 * 1024) AS mb, display_value, isdefault, descriptionFROM v$parameterWHERE name = 'db_cache_size';
-- Check actual runtime buffer cache size (ASMM may differ from parameter)SELECT component, current_size / (1024 * 1024) AS current_mb, min_size / (1024 * 1024) AS min_mb, max_size / (1024 * 1024) AS max_mb, user_specified_size / (1024*1024) AS floor_mb, last_oper_type, last_oper_modeFROM v$sga_dynamic_componentsWHERE component = 'DEFAULT buffer cache';
-- Check all buffer pools (DEFAULT, KEEP, RECYCLE, and nK caches)SELECT component, current_size / (1024 * 1024) AS current_mbFROM v$sga_dynamic_componentsWHERE component LIKE '%buffer%' OR component LIKE '%cache%'ORDER BY current_size DESC;Setting the Parameter
Section titled “Setting the Parameter”-- Set a floor when using ASMM (SGA_TARGET > 0) — Oracle manages above thisALTER SYSTEM SET db_cache_size = 2G SCOPE = BOTH;
-- Set fixed size when NOT using ASMM (manual SGA)ALTER SYSTEM SET db_cache_size = 8G SCOPE = BOTH;
-- Increase buffer cache immediately (no restart needed)ALTER SYSTEM SET db_cache_size = 4G SCOPE = BOTH;
-- Persist to SPFILE only (takes effect at next restart)ALTER SYSTEM SET db_cache_size = 4G SCOPE = SPFILE;
-- Return to full ASMM control (remove the floor)ALTER SYSTEM SET db_cache_size = 0 SCOPE = BOTH;Tuning Guidance
Section titled “Tuning Guidance”Recommended Values
Section titled “Recommended Values”| Environment | Profile | Suggested DB_CACHE_SIZE / SGA Allocation | Notes |
|---|---|---|---|
| OLTP, small (< 16 GB RAM) | High concurrency, small rows | 50–60% of SGA | Many small block reads |
| OLTP, large (64+ GB RAM) | Connection pooling | 70–80% of SGA | Maximize cache; pool reduces session overhead |
| Data Warehouse | Full scans, large tables | 30–50% of SGA | Direct path reads bypass cache; balance with PGA |
| Mixed workload | OLTP + reporting | 60–70% of SGA | Shared pool also needs headroom |
| Read-mostly, hot dataset fits in RAM | Pure cache hit scenario | Dataset size + 20% buffer | Near 100% hit ratio achievable |
How to Size
Section titled “How to Size”V$DB_CACHE_ADVICE is the definitive tool for buffer cache sizing. Oracle continuously simulates what the physical read count would be at different cache sizes.
-- V$DB_CACHE_ADVICE: model reads at different cache sizes-- Run after at least 30 minutes of representative workloadSELECT size_for_estimate / (1024 * 1024) AS cache_size_mb, size_factor, buffers_for_estimate, estd_physical_read_factor, estd_physical_readsFROM v$db_cache_adviceWHERE name = 'DEFAULT'AND block_size = (SELECT value FROM v$parameter WHERE name = 'db_block_size')AND advice_status = 'ON'ORDER BY size_for_estimate;Reading the output: estd_physical_read_factor of 1.0 represents the current cache size. Values < 1.0 mean fewer reads (better) with a larger cache. Look for the point where the factor flattens — adding more cache beyond that point gives minimal additional benefit.
-- Ensure cache advice is enabled (should be ON by default)SELECT name, value FROM v$parameter WHERE name = 'db_cache_advice';
-- Enable if not runningALTER SYSTEM SET db_cache_advice = ON;Buffer Cache Hit Ratio
Section titled “Buffer Cache Hit Ratio”-- Overall buffer cache hit ratio (logical vs physical reads)-- Target: > 90% for OLTP; data warehouses with direct-path reads will be lowerSELECT 1 - (phy.value / (cur.value + con.value)) AS hit_ratio, ROUND((1 - (phy.value / (cur.value + con.value))) * 100, 2) AS hit_ratio_pct, cur.value AS db_block_gets, con.value AS consistent_gets, phy.value AS physical_readsFROM v$sysstat cur, v$sysstat con, v$sysstat phyWHERE cur.name = 'db block gets'AND con.name = 'consistent gets'AND phy.name = 'physical reads';
-- Per-segment physical reads (identify hot objects driving I/O)SELECT owner, object_name, object_type, physical_reads, db_block_changes, logical_reads, ROUND(physical_reads / NULLIF(logical_reads, 0) * 100, 2) AS phys_read_pctFROM v$segment_statisticsWHERE statistic_name = 'physical reads'AND physical_reads > 0ORDER BY physical_reads DESCFETCH FIRST 20 ROWS ONLY;
-- Physical reads vs logical reads trend (from AWR, requires Diagnostics Pack)SELECT snap_id, SUM(CASE WHEN stat_name = 'physical reads' THEN value END) AS phys_reads, SUM(CASE WHEN stat_name = 'logical reads' THEN value END) AS logical_readsFROM dba_hist_sysstatWHERE stat_name IN ('physical reads', 'logical reads')AND snap_id > (SELECT MAX(snap_id) - 48 FROM dba_hist_snapshot)GROUP BY snap_idORDER BY snap_id;Monitoring
Section titled “Monitoring”-- Monitor buffer cache current stateSELECT name, block_size, current_size / (1024 * 1024) AS current_mb, buffersFROM v$buffer_poolORDER BY current_size DESC;
-- Check for buffer busy waits (indicates cache contention, not size issue)SELECT event, total_waits, time_waited_micro / 1000 AS time_waited_ms, average_waitFROM v$system_eventWHERE event IN ('buffer busy waits', 'read by other session', 'db file sequential read', 'db file scattered read')ORDER BY total_waits DESC;
-- Objects with highest buffer cache residency (what is actually in cache)SELECT owner, segment_name, segment_type, COUNT(*) AS cached_blocks, COUNT(*) * s.block_size / (1024 * 1024) AS cached_mbFROM v$bh bJOIN dba_extents e ON b.file# = e.file_id AND b.block# BETWEEN e.block_id AND e.block_id + e.blocks - 1JOIN dba_segments s ON e.owner = s.owner AND e.segment_name = s.segment_nameWHERE b.status != 'free'GROUP BY owner, segment_name, segment_type, s.block_sizeORDER BY cached_blocks DESCFETCH FIRST 20 ROWS ONLY;Common Issues
Section titled “Common Issues”Low buffer cache hit ratio despite large cache
Section titled “Low buffer cache hit ratio despite large cache”A hit ratio below 90% in an OLTP environment usually has one of three causes: the cache is genuinely too small, there are large-table full scans polluting the cache, or direct-path reads are bypassing the cache (expected for data warehouses).
-- Identify full scans that may be polluting the buffer cacheSELECT sql_id, disk_reads, buffer_gets, rows_processed, ROUND(disk_reads / NULLIF(buffer_gets, 0) * 100, 2) AS disk_read_pct, SUBSTR(sql_text, 1, 100) AS sql_textFROM v$sqlWHERE disk_reads > 10000ORDER BY disk_reads DESCFETCH FIRST 20 ROWS ONLY;
-- Move large lookup tables to the KEEP pool to protect them from eviction-- First, create the KEEP poolALTER SYSTEM SET db_keep_cache_size = 512M SCOPE = BOTH;
-- Then assign objects to itALTER TABLE schema.large_lookup_table STORAGE (BUFFER_POOL KEEP);ORA-04031 from buffer cache growth reducing shared pool
Section titled “ORA-04031 from buffer cache growth reducing shared pool”Under ASMM, when you increase DB_CACHE_SIZE, Oracle may shrink the shared pool to compensate within SGA_TARGET. If the shared pool shrinks too much, ORA-04031 can occur.
-- Increase SGA_TARGET to give both pools room to growALTER SYSTEM SET sga_target = 12G SCOPE = BOTH;
-- Or set explicit floors for both componentsALTER SYSTEM SET db_cache_size = 8G SCOPE = BOTH;ALTER SYSTEM SET shared_pool_size = 1G SCOPE = BOTH;-- Total floors must not exceed SGA_TARGETBuffer cache decrease fails at runtime
Section titled “Buffer cache decrease fails at runtime”Shrinking DB_CACHE_SIZE online may fail if pinned or dirty blocks occupy the memory Oracle is trying to release.
-- Check how much of the cache is dirty or pinnedSELECT status, COUNT(*) AS buffer_count, ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (), 2) AS pctFROM v$bhGROUP BY statusORDER BY buffer_count DESC;-- Statuses: free, xcur (exclusive current), scur (shared current), cr (consistent read), read, mrec, irecIf the shrink is urgent, checkpoint the database to flush dirty buffers, then retry the resize.
ALTER SYSTEM CHECKPOINT;ALTER SYSTEM SET db_cache_size = 2G SCOPE = BOTH;Related Parameters
Section titled “Related Parameters”| Parameter | Relationship |
|---|---|
SGA_TARGET | Enables ASMM; DB_CACHE_SIZE becomes a minimum floor when set |
MEMORY_TARGET | Enables AMM; DB_CACHE_SIZE still acts as a floor |
DB_KEEP_CACHE_SIZE | Separate pool for objects marked BUFFER_POOL KEEP |
DB_RECYCLE_CACHE_SIZE | Separate pool for objects marked BUFFER_POOL RECYCLE |
DB_BLOCK_SIZE | Block size of the default cache; must match when creating the database |
DB_nK_CACHE_SIZE | Caches for non-standard block sizes (2K, 4K, 8K, 16K, 32K) |
DB_CACHE_ADVICE | Enables/disables V$DB_CACHE_ADVICE simulation (default ON) |
Related Errors
Section titled “Related Errors”Version Notes
Section titled “Version Notes”| Version | Notes |
|---|---|
| 9i | DB_CACHE_SIZE introduced; replaces DB_BLOCK_BUFFERS |
| 10g | V$DB_CACHE_ADVICE fully operational; ASMM widely used |
| 11g | AMM (MEMORY_TARGET) makes DB_CACHE_SIZE a floor under combined pool |
| 12c | In-Memory Column Store (INMEMORY_SIZE) competes for SGA budget alongside buffer cache |
| 19c+ | Direct NFS and SmartScan (Exadata) can reduce cache effectiveness for full scans |
| 21c+ | No functional change; ASMM or AMM with a floor remains best practice |