AWR (Automatic Workload Repository) and ASH (Active Session History) are Oracle's most powerful built-in diagnostic tools, but most DBAs only look at the top few sections. This guide walks through every section of both reports — what each metric means, what's normal, and what's a red flag.
AWR snapshots ~1,200 cumulative statistics every 60 minutes (default) and stores them in SYSAUX. A report compares two snapshots to show delta activity. The key thing to understand: AWR shows averages over the interval — a 60-minute report with one 5-minute crisis looks fine. Use ASH for point-in-time diagnosis.
-- Generate AWR report manually
@$ORACLE_HOME/rdbms/admin/awrrpt.sql
-- Check snapshot availability
SELECT snap_id, begin_interval_time, end_interval_time
FROM dba_hist_snapshot
ORDER BY snap_id DESC
FETCH FIRST 10 ROWS ONLY;
-- AWR settings
SELECT snap_interval, retention
FROM dba_hist_wr_control;
Default retention is 8 days, interval 60 minutes. For busy production systems, consider increasing retention to 30 days and decreasing interval to 30 minutes for better granularity.
The very first section shows elapsed time, DB Time, and CPUs. DB Time is the single most important number in the entire report.
Snap Id Snap Time Sessions Curs/Sess
------- --------- -------- ---------
Begin: 100 01-Jul-26 09:00:00 245 3.2
End: 101 01-Jul-26 10:00:00 251 3.3
Elapsed: 60.05 (mins)
DB Time: 387.23 (mins)
DB Time = sum of all time all sessions spent doing work (CPU + wait events). With 8 CPUs and a 60-minute interval, your theoretical maximum DB Time is 480 minutes (8 × 60). A DB Time of 387 minutes means you're using ~80% of CPU capacity — which is high but not yet critical.
If DB Time significantly exceeds CPUs × elapsed time, you have more demand than CPU can service — either add CPUs, optimize SQL, or reduce workload.
Per Second Per Transaction
---------- ---------------
Logical reads: 45,823.2 1,234.5
Block changes: 1,203.4 32.4
Physical reads: 2,341.2 63.1
Physical writes: 456.7 12.3
User calls: 1,234.5 33.2
Parses: 892.3 24.0
Hard parses: 23.4 0.6
Executes: 3,456.7 93.1
What to look for:
Buffer Nowait %: 99.98 Redo NoWait %: 99.99
Buffer Hit %: 97.23 In-memory Sort %: 99.87
Library Hit %: 99.12 Soft Parse %: 97.38
Execute to Parse %: 74.23 Latch Hit %: 99.94
Parse CPU to Parse Elapsd %: 45.23
% Non-Parse CPU: 99.12
Thresholds that matter:
This section shows where DB Time was actually spent. Every tuning exercise starts here.
Top 5 Timed Events
~~~~~~~~~~~~~~~~~~ % Total
Event Waits Time (s) Avg Wait DB Time
-------------------------- -------- --------- -------- -------
db file sequential read 234,567 1,823.4 7.77 78.4%
CPU time 389.2 16.7%
log file sync 12,345 89.3 7.23 3.8%
db file scattered read 3,456 34.5 9.99 1.5%
latch: shared pool 234 8.9 38.0 0.4%
How to read this:
Wait event categories to know:
SQL ordered by Elapsed Time
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Resources Reported for PL/SQL Code Includes Code executed by Code
Elapsed CPU IO Executions Elapsed Time
Time (s) Executions Time (s) Waits (s) Per Exec (s) SQL Id
---------- ---------- -------- --------- ------------ ------------ --------
1,234.56 12 234.56 1,000.00 12 102.88 a1b2c3d4e
This is your primary SQL tuning target list. Look for:
-- Pull the actual SQL text and current plan
SELECT sql_text FROM dba_hist_sqltext WHERE sql_id = 'a1b2c3d4e';
-- Historical execution stats
SELECT snap_id, executions, elapsed_time/1000000 elapsed_s,
buffer_gets, disk_reads
FROM dba_hist_sqlstat
WHERE sql_id = 'a1b2c3d4e'
ORDER BY snap_id DESC;
High logical reads mean a SQL is touching many buffer cache blocks — either due to large result sets, missing indexes, or bad plans. A single SQL with 100M buffer gets per execution is a tuning emergency regardless of its elapsed time.
High parse calls with low executions means bind variables are missing — the application is sending a new literal value each time (WHERE id = 1234, WHERE id = 1235, ...) instead of WHERE id = :bind_var. Each unique literal = a new cursor = a hard parse = shared pool fragmentation.
Memory Statistics
~~~~~~~~~~~~~~~~~
Begin End
SGA use (MB): 4,096 4,097
PGA use (MB): 1,234 1,289
SGA breakdown:
Buffer Cache: 2,048 MB
Shared Pool: 1,024 MB
Large Pool: 64 MB
Java Pool: 64 MB
Streams Pool: 32 MB
Cross-reference with Instance Efficiency:
Tablespace IO Stats
~~~~~~~~~~~~~~~~~~~
Tablespace Reads Av Reads/s Av Rd(ms) Writes Av Writes/s
------------------ ----- ---------- --------- ------ -----------
APPS_TS_TX_DATA 45,678 12.66 8.23 12,345 3.43
UNDOTBS1 2,345 0.65 3.45 456 0.13
SYSTEM 123 0.03 2.12 45 0.01
Key metric: Av Rd(ms) — average read time in milliseconds.
Hot tablespaces with high average read times are candidates for moving to faster storage.
While AWR averages 60 minutes, ASH samples every active session every second and keeps the last 30-60 minutes in memory (plus history in DBA_HIST_ACTIVE_SESS_HISTORY). This is your point-in-time diagnostic tool.
-- What was happening 30 minutes ago?
SELECT event, COUNT(*) sessions
FROM v$active_session_history
WHERE sample_time BETWEEN SYSDATE - 40/1440 AND SYSDATE - 30/1440
GROUP BY event
ORDER BY sessions DESC;
-- Top SQL by ASH samples (= time consuming)
SELECT sql_id, COUNT(*) samples,
ROUND(COUNT(*)/SUM(COUNT(*)) OVER () * 100, 1) pct
FROM v$active_session_history
WHERE sample_time > SYSDATE - 1/24
GROUP BY sql_id
ORDER BY samples DESC
FETCH FIRST 10 ROWS ONLY;
-- Session timeline for a specific SQL
SELECT TO_CHAR(sample_time,'HH24:MI:SS') sample_time,
session_id, session_serial#,
event, wait_class, sql_plan_hash_value
FROM v$active_session_history
WHERE sql_id = 'a1b2c3d4e'
AND sample_time > SYSDATE - 1/24
ORDER BY sample_time;
The ASH report (@$ORACLE_HOME/rdbms/admin/ashrpt.sql) is structured differently from AWR:
Top User Events — what were sessions waiting on. Unlike AWR's Top 5 which averages the whole period, ASH shows you the distribution over time. You can see a spike at 10:15 that the AWR average buried.
Top Background Events — what LGWR, DBWR, CKPT, and other background processes were doing. High background waits often indicate I/O subsystem issues independent of user activity.
Top SQL with Top Events — combines SQL identity with wait events. This tells you not just which SQL is slow but why it's slow (I/O waits vs CPU vs locking).
Activity Over Time — the timeline chart showing session count by wait class per minute. This is where you identify the exact minute something went wrong. A spike in Application waits at 10:14 correlates to the batch job that ran at 10:13.
-- What's happening right now — sessions by wait event
SELECT event, wait_class, COUNT(*) active_sessions,
LISTAGG(sql_id, ',') WITHIN GROUP (ORDER BY sql_id) sql_ids
FROM v$session
WHERE status = 'ACTIVE'
AND type = 'USER'
AND wait_class != 'Idle'
GROUP BY event, wait_class
ORDER BY active_sessions DESC;
-- Find the blocking session chain
SELECT level, s.sid, s.serial#, s.username,
s.event, s.wait_class,
s.blocking_session,
s.sql_id,
s.seconds_in_wait
FROM v$session s
START WITH s.blocking_session IS NULL
AND s.status = 'ACTIVE'
AND s.type = 'USER'
CONNECT BY PRIOR s.sid = s.blocking_session
ORDER SIBLINGS BY seconds_in_wait DESC;
TuneVault's Performance Advisor automates this entire workflow — running ADDM analysis across your AWR snapshot history and surfacing the top findings ranked by DB Time impact. Rather than reading 40-page AWR reports manually, you get the three things that matter most and the exact SQL to fix them. Connect at tunevault.app to run your first ADDM analysis.