Home / Databases / Oracle

DatabasesCheat sheetAdvanced

Oracle RAC global cache waits cheat sheet: gc buffer busy, gc cr/current block waits, lost blocks and hot objects

Queries and decision tables for RAC global cache waits. Tell interconnect problems from application contention, find the hot blocks and objects, and pick the right fix.

Deepak Bhardwaj7 min read

Applies toOracle Database 19c and 23ai RAC (on-premises, Exadata, OCI Base Database, Exadata Database Service). ASH and AWR queries need the Diagnostics Pack licence.

When to use this

A RAC database is slower than the same workload on one node, and gc wait events dominate AWR or ASH. The work is always the same: decide whether the interconnect is slow or the application makes instances fight over the same blocks. The two look alike in top-event lists and have opposite fixes.

The wait events that matter

Event What it means Usual direction
gc cr block 2-way / 3-way Consistent-read block shipped from another instance (2 or 3 hops) Normal at low latency; high count means cross-instance reads
gc current block 2-way / 3-way Current block shipped for modification Normal at low latency; high count means cross-instance writes
gc cr grant 2-way, gc current grant 2-way Master grants permission to read from disk; no block shipped Usually I/O-bound, not interconnect
gc buffer busy acquire Another session on this instance is already fetching the block Hot block, application contention
gc buffer busy release Another instance requested a block this instance holds busy Hot block across instances
gc cr block busy, gc current block busy Holder had to do work (flush redo, build CR copy) before shipping Slow LGWR on the holder or heavy contention
gc cr block congested, gc current block congested LMS on the holder was too busy to respond quickly LMS CPU starvation or too few LMS processes
gc cr block lost, gc current block lost Block sent but not received; resent after a timeout Interconnect network problem. Never normal
gc cr multi block request Multiblock reads of blocks cached elsewhere Full scans across instances

Rule of thumb: high average times on 2-way/3-way events with no busy or congested point to the network or LMS. High busy counts with normal 2-way times point to the application.

Average block receive times per instance

SELECT inst_id,
       SUM(DECODE(name, 'gc cr blocks received', value))           AS cr_blocks,
       ROUND(10 * SUM(DECODE(name, 'gc cr block receive time', value)) /
             NULLIF(SUM(DECODE(name, 'gc cr blocks received', value)), 0), 2) AS avg_cr_ms,
       SUM(DECODE(name, 'gc current blocks received', value))      AS cur_blocks,
       ROUND(10 * SUM(DECODE(name, 'gc current block receive time', value)) /
             NULLIF(SUM(DECODE(name, 'gc current blocks received', value)), 0), 2) AS avg_cur_ms
FROM   gv$sysstat
WHERE  name IN ('gc cr blocks received', 'gc cr block receive time',
                'gc current blocks received', 'gc current block receive time')
GROUP  BY inst_id
ORDER  BY inst_id;

Receive times are in centiseconds, hence the * 10 for milliseconds. Values are cumulative since startup; for an incident use AWR deltas or sample twice. On a healthy private interconnect, averages are typically well under a millisecond; Exadata with RDMA is lower still. Compare against your own baseline.

Lost and congested blocks

SELECT inst_id, name, value
FROM   gv$sysstat
WHERE  name IN ('gc blocks lost', 'gc blocks corrupt')
ORDER  BY inst_id, name;

Transfer quality by peer instance and block class:

SELECT inst_id, instance AS from_inst, class,
       cr_block, cr_busy, cr_congested,
       current_block, current_busy, current_congested
FROM   gv$instance_cache_transfer
WHERE  cr_block + current_block > 0
ORDER  BY cr_busy + current_busy DESC
FETCH FIRST 20 ROWS ONLY;

busy concentrated on data block points at hot table blocks; on undo header or undo block it points at hot rows being read while modified elsewhere.

Which sessions are waiting right now

SELECT inst_id, event, COUNT(*) AS sessions,
       ROUND(AVG(seconds_in_wait), 1) AS avg_sec
FROM   gv$session
WHERE  wait_class = 'Cluster'
  AND  state = 'WAITING'
GROUP  BY inst_id, event
ORDER  BY sessions DESC;

Hot objects and blocks from ASH

Last 30 minutes, top objects behind Cluster waits:

SELECT ash.current_obj#, o.owner, o.object_name, o.subobject_name, o.object_type,
       ash.event, COUNT(*) AS samples
FROM   gv$active_session_history ash
LEFT JOIN dba_objects o ON o.object_id = ash.current_obj#
WHERE  ash.sample_time > SYSTIMESTAMP - INTERVAL '30' MINUTE
  AND  ash.wait_class = 'Cluster'
GROUP  BY ash.current_obj#, o.owner, o.object_name, o.subobject_name, o.object_type, ash.event
ORDER  BY samples DESC
FETCH FIRST 15 ROWS ONLY;

Single hot blocks:

SELECT current_obj#, current_file#, current_block#, event, COUNT(*) AS samples
FROM   gv$active_session_history
WHERE  sample_time > SYSTIMESTAMP - INTERVAL '30' MINUTE
  AND  event LIKE 'gc buffer busy%'
GROUP  BY current_obj#, current_file#, current_block#, event
ORDER  BY samples DESC
FETCH FIRST 10 ROWS ONLY;

If a few blocks have most of the samples, it is a hot block problem. Look at the block to see whether it is the right edge of an index, a segment header or a single popular row.

Top SQL behind the waits:

SELECT sql_id, event, COUNT(*) AS samples
FROM   gv$active_session_history
WHERE  sample_time > SYSTIMESTAMP - INTERVAL '30' MINUTE
  AND  wait_class = 'Cluster'
GROUP  BY sql_id, event
ORDER  BY samples DESC
FETCH FIRST 10 ROWS ONLY;

For history beyond the ASH buffer, use dba_hist_active_sess_history with the same columns and sample_time filter.

Segment-level statistics

SELECT owner, object_name, subobject_name, statistic_name, SUM(value) AS total
FROM   gv$segment_statistics
WHERE  statistic_name IN ('gc buffer busy', 'gc cr blocks received', 'gc current blocks received')
GROUP  BY owner, object_name, subobject_name, statistic_name
ORDER  BY total DESC
FETCH FIRST 20 ROWS ONLY;

This catches objects that are steadily expensive even outside an incident.

Interconnect checks

SELECT inst_id, name, ip_address, is_public, source
FROM   gv$cluster_interconnects;

Confirm every instance uses the private network you expect, not the public one. Then on each node, as the Grid owner:

oifcfg getif
netstat -s | grep -iE 'reassembl|fragments|packet receive errors|buffer errors'
ip -s link show <private_nic>

Rising reassembly failures, receive buffer errors or interface drops line up with gc ... lost. Common causes: MTU mismatch along the path (jumbo frames on hosts but not the switch), undersized socket buffers (net.core.rmem_max), a bad NIC or cable, or a saturated bonded link. Check the LMS processes are not starved:

ps -eo pid,pri,ni,pcpu,comm | grep -E 'ora_lms|ora_lm'

Warning

Lost blocks can escalate to node evictions if the interconnect degrades further. Treat any non-zero, growing gc blocks lost as a network incident, not a tuning task.

Symptom → cause → fix

Symptom Likely cause Fix
High avg 2-way time, no busy, lost > 0 Interconnect drops or MTU mismatch Fix network path; verify MTU end to end; check socket buffers
High avg time, congested events LMS short on CPU Free CPU on the node; check LMS priority; review gcs_server_processes with Oracle Support
gc buffer busy on one index's right edge Monotonic key (sequence, timestamp) inserted from all instances Hash-partition the index, or route inserts for the table to one service; use a scalable sequence on 18c+ (CREATE SEQUENCE ... SCALE)
gc buffer busy on a small table Popular status/counter row updated from all nodes Redesign the counter, or run that workload on one instance via a service
High gc current block busy Holder waits for log flush before shipping Fix redo latency (log file parallel write) on the holder
Sequence-related waits ORDER sequence or small CACHE ALTER SEQUENCE s CACHE 1000 NOORDER; where gaps and ordering are acceptable
Many gc cr multi block request Full scans of tables modified on other nodes Tune the SQL, or run reports where the data is modified

Prevent it next time

  • Design services so each workload's writes land on one instance where possible, with others as available instances for failover.
  • Baseline avg CR and current receive times per instance and alert on a sustained doubling or any growing lost-block count.
  • Review AWR's "Global Cache Load Profile" and "Global Cache Efficiency" sections monthly.
  • Avoid ORDER sequences and right-growing indexes on tables written from every node; test inserts from all instances before go-live.
  • Keep interconnect MTU, NIC firmware and kernel network settings identical across nodes and check them after any network change.