Reading Oracle AWR & ASH Reports: Wait-Event Troubleshooting
"The database is slow." Every DBA hears it, and the panic answer โ start changing parameters โ usually makes things worse. The disciplined answer is to let the database tell you what it's waiting on. Oracle's AWR and ASH reports do exactly that. After 18+ years of production firefighting across banking, pharma, and ERP systems, I've learned that almost every performance problem becomes obvious once you read these reports in the right order. Here is that order.
1. AWR vs ASH โ Pick the Right Lens
- AWR aggregates activity between two snapshots (usually hourly). Use it for "the system was slow this afternoon" โ trends and overall load.
- ASH samples every active session once per second. Use it for "it froze for 90 seconds at 2:14 pm" โ short, sharp spikes an hourly average would smooth away.
Rule of thumb: AWR for the hour, ASH for the moment.
2. Generating the Reports
-- AWR (pick begin/end snapshot IDs when prompted)
@?/rdbms/admin/awrrpt.sql
-- ASH for a specific window
@?/rdbms/admin/ashrpt.sql
-- list recent snapshots
SELECT snap_id, begin_interval_time
FROM dba_hist_snapshot
ORDER BY snap_id DESC FETCH FIRST 12 ROWS ONLY;
Keep the AWR window tight โ one hour that covers the problem beats a six-hour report that averages the pain away.
3. Start at the Top: DB Time and Load Profile
Don't scroll to the wait events first. Read the header. DB Time is the total time sessions spent working plus waiting. Compare it to elapsed time: 60 minutes elapsed with 600 minutes of DB Time means heavy concurrency.
The Load Profile tells you the shape of the workload โ per second and per transaction:
- DB Time / sec โ average active sessions; the single best "how busy" number.
- Logical & physical reads โ is the work in memory or on disk?
- Hard parses / sec โ high values scream "no bind variables".
- Redo size, commits, rollbacks โ write intensity and transaction pattern.
4. The Heart of It: Top Foreground Wait Events
This section ranks where DB Time actually went. The top two or three events are your problem โ everything below is noise. Read them as a sentence: "the database spent most of its time waiting on ____." Then fix that.
5. The Wait Events You'll Actually See
- db file sequential read โ single-block (index) reads from disk. High = physical I/O from missing/poor indexes, small buffer cache, or a query reading too many blocks.
- db file scattered read โ multi-block full-scan reads. High = full table scans that may need an index, or a deliberately large scan.
- log file sync โ sessions waiting on COMMIT to flush redo. High = too-frequent commits or slow redo storage. Look at commits/sec and log writer latency.
- buffer busy waits โ contention for the same blocks; often hot blocks or insufficient freelists/ASSM pressure.
- library cache / cursor: pin S wait on X โ parsing contention, usually literal SQL instead of bind variables.
- gc buffer busy / gc cr block busy (RAC) โ cross-instance block contention. Check interconnect latency and hot-block design.
- enq: TX - row lock contention โ application locking; one session blocking others on the same row.
- CPU time at the top โ not a wait at all; the database is busy computing. Find the SQL burning the CPU.
6. Follow the Wait to the SQL
A wait event tells you the symptom; the SQL section names the culprit. Read SQL ordered by Elapsed Time and by Gets, grab the worst SQL_ID, and pull its plan:
SELECT * FROM TABLE(
DBMS_XPLAN.DISPLAY_AWR('&sql_id'));
-- or the live plan from cursor cache
SELECT * FROM TABLE(
DBMS_XPLAN.DISPLAY_CURSOR('&sql_id', NULL, 'ALLSTATS LAST'));
Now the story closes: high db file sequential read + a top SQL doing a huge INDEX RANGE SCAN into a TABLE ACCESS BY ROWID on millions of rows = the index or the query needs work.
7. ASH for the Transient Spike
When the freeze lasted seconds, query ASH directly for that window:
SELECT event, COUNT(*) AS samples
FROM v$active_session_history
WHERE sample_time BETWEEN TIMESTAMP '2026-06-12 14:13:00'
AND TIMESTAMP '2026-06-12 14:16:00'
GROUP BY event
ORDER BY samples DESC;
Each sample โ one second of one active session, so the counts approximate seconds of wait. You'll often see a single blocking session or one event dominate the spike that AWR completely averaged out.
8. Let ADDM Give You a Second Opinion
Oracle's Automatic Database Diagnostic Monitor reads the AWR data and writes findings in plain language โ a useful sanity check, not a replacement for judgement:
@?/rdbms/admin/addmrpt.sql
Treat ADDM findings as leads to verify, not orders to follow blindly.
9. A Repeatable Troubleshooting Workflow
- Scope it โ exact time window and symptom. Hour-long? AWR. Seconds? ASH.
- Read DB Time & Load Profile โ how busy, in memory or on disk, parsing hard?
- Read the top 2โ3 wait events โ name what the database waited on.
- Map wait โ SQL โ find the statement responsible and read its plan.
- Form one hypothesis, make one change โ index, bind variables, commit frequency, memory.
- Re-measure โ confirm DB Time dropped before declaring victory.
10. Mistakes That Waste Hours
- Chasing buffer cache hit ratios โ a near-100% ratio can hide a query doing millions of logical reads. Tune the SQL, not the ratio.
- Reports that are too wide โ a 4-hour AWR averages the incident into invisibility.
- Changing many things at once โ you'll never know which one helped (or hurt).
- Ignoring the application โ row-lock contention and literal SQL are code problems, not parameter problems.
- Tuning without a baseline โ keep a "good day" AWR to compare against.
Final Thoughts
Performance tuning stops being guesswork the moment you trust the instrumentation. AWR and ASH don't hide the answer โ they hand it to you, if you read them top-down: how busy, waiting on what, caused by which SQL. Resist the urge to change parameters from memory. Measure, form one hypothesis, change one thing, measure again. That discipline is the entire difference between a DBA who calms an incident and one who prolongs it.
If you have a recurring slowdown, a month-end spike, or an AWR report you'd like a second pair of eyes on, let's talk. I diagnose and tune production Oracle performance for banking, pharma, and ERP systems and can help you find the real bottleneck quickly.
๐ Database Running Slow?
AWR/ASH analysis, SQL tuning, and root-cause performance diagnosis. Free 30-minute consultation.
References & Further Reading
- ๐ Oracle Database Performance Tuning Guide (19c)
- ๐ Automatic Performance Diagnostics โ AWR & ADDM
- ๐ V$ACTIVE_SESSION_HISTORY Reference
This guide is based on hands-on Oracle performance troubleshooting across banking, pharma, and ERP systems and Oracle's official documentation.
