Chapter 22 · Observability and Diagnostics: AWR, ASH, ADDM, Wait Events, and Tracing
Dynamic Performance Views for Sessions, SQL, Locks, I/O, Memory, and Instance Health
Answer concrete live incident questions from Oracle dynamic performance views, using bounded snapshots and container-aware interpretation instead of treating cumulative/transient V$ state as durable history.
Learning outcomes
ServiceHub users report “the database is slow right now.” Before
reaching for historical reports, the DBA needs to answer
immediate questions: Which sessions are active? Which SQL are
they running? Is one session blocking another? Are reads/writes
increasing? Is memory pressure visible? Are process/session
limits near their configured ceilings? Oracle's
dynamic performance views—the
V$/GV$ family—expose live instance
state and cumulative counters.
Use V$SESSION and V$SQL to identify active work without mistaking one sample for history.
Diagnose a real row-lock blocker with V$SESSION and V$LOCK, then repair it by ending the correct transaction.
Read file I/O, SGA/PGA and resource-limit evidence from pack-independent dynamic views.
Explain why cumulative counters require two snapshots and why cursor/session state can disappear.
Apply CDB/PDB and RAC scope correctly: V$ is local/current-container-aware; GV$ adds instance identity in RAC.
Mandatory examples target Oracle AI Database Free 26ai, reviewed against RU 23.26.3, SQL Developer 26.2, and SQLcl 26.2.1. Free is limited to 2 foreground CPU cores, 2 GB combined SGA/PGA memory, 12 GB user data, and one installation per logical environment; Oracle provides no Release Update patches or Support service requests for Free. The course CDB/PDB baseline is FREE/FREEPDB1. Core dynamic performance views, DBMS_XPLAN runtime plans, DBMS_MONITOR SQL trace and TKPROF are used as the pack-independent diagnostic lane. Current 26ai licensing includes Oracle Diagnostics Pack and Oracle Tuning Pack in Free, but each is an extra-cost pack on EE/EE-ES. AWR, ADDM and V$ACTIVE_SESSION_HISTORY belong to Diagnostics Pack; Real-Time SQL/PLSQL Monitoring belongs to Tuning Pack and also requires Diagnostics Pack. CONTROL_MANAGEMENT_PACK_ACCESS defaults to DIAGNOSTIC+TUNING on both Free and Enterprise Edition, so a value of DIAGNOSTIC+TUNING proves functional enablement—not that an EE/EE-ES customer purchased the packs. Never query AWR/ASH/ADDM/SQL Monitor merely because the views exist on an EE/EE-ES system whose entitlement is unknown.
1. Dynamic views answer “what is true now?”
V$SESSION exposes session identity/state,
V$SQL exposes cursor-level SQL statistics,
V$SYSTEM_EVENT/V$SESSION_EVENT expose
cumulative waits, and specialized views expose locks, files,
memory and configured resource utilization. Most values are
memory-derived and reset/recycle with instance restart, session
end, cursor aging/reload or object lifecycle.
SELECT SYS_CONTEXT('USERENV','CON_NAME') AS con_name, SYS_CONTEXT('USERENV','CON_ID') AS con_id, SYS_CONTEXT('USERENV','INSTANCE_NAME') AS instance_nameFROM dual;SELECT instance_name,startup_time,statusFROM v$instance;
2. Active sessions: status, event, SQL and application identity
SELECT sid, serial#, username, status, service_name, module, action, client_identifier, sql_id, event, wait_class, seconds_in_waitFROM v$sessionWHERE type='USER'ORDER BY status DESC,sid;
ACTIVE means the session is executing a database
call—not necessarily consuming CPU. An active session can be
waiting on I/O, a lock, network or another resource.
INACTIVE can be healthy connection-pool idleness.
3. Join the SQL ID to cursor statistics
SELECT sql_id, child_number, plan_hash_value, executions, rows_processed, buffer_gets, disk_reads, cpu_time, elapsed_time, parse_calls, substr(sql_text,1,120) AS sql_textFROM v$sqlWHERE sql_id=:sql_idORDER BY child_number;
These are cumulative cursor statistics. A high lifetime
BUFFER_GETS can simply mean a very frequently
executed healthy SQL statement. Normalize by executions and take
interval deltas before calling it the current incident cause.
4. Reproducible blocking lab
BEGIN EXECUTE IMMEDIATE 'DROP TABLE sh22_lock_case PURGE';EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF;END;/CREATE TABLE sh22_lock_case ( case_id NUMBER PRIMARY KEY, status_code VARCHAR2(12) NOT NULL, amount NUMBER(10,2) NOT NULL);INSERT INTO sh22_lock_case VALUES(1,'OPEN',100);INSERT INTO sh22_lock_case VALUES(2,'OPEN',200);COMMIT;
BEGIN DBMS_APPLICATION_INFO.SET_MODULE('SH22_LOCK_LAB','HOLDER');END;/UPDATE sh22_lock_caseSET amount=amount+10WHERE case_id=1;-- Do NOT commit yet.
BEGIN DBMS_APPLICATION_INFO.SET_MODULE('SH22_LOCK_LAB','WAITER');END;/UPDATE sh22_lock_caseSET status_code='HOLD'WHERE case_id=1;-- This call waits until Session A commits/rolls back or a timeout/interrupt occurs.
5. Diagnose the blocker from a third/admin session
SELECT sid, serial#, module, action, status, event, wait_class, seconds_in_wait, blocking_instance, blocking_session, final_blocking_session, sql_idFROM v$sessionWHERE module='SH22_LOCK_LAB'ORDER BY sid;
The waiter should show an enqueue event such as
enq: TX - row lock contention and identify Session
A as the blocker. The blocker may show
INACTIVE while holding an open
transaction—important proof that inactive does not mean
harmless.
SELECT sid, type, id1, id2, lmode, request, block, ctimeFROM v$lockWHERE sid IN ( SELECT sid FROM v$session WHERE module='SH22_LOCK_LAB')ORDER BY type,sid;
The TX enqueue rows expose holder/requester state.
They do not tell you whether the business transaction should be
committed or rolled back; application/owner context decides the
safe repair.
6. Safe repair: end the correct transaction
ROLLBACK;-- Session B can now proceed with its UPDATE.
ROLLBACK;BEGIN DBMS_APPLICATION_INFO.SET_MODULE(NULL,NULL);END;/
Do not kill a blocker as the first reaction. A forced session kill can trigger rollback of a large transaction and prolong the incident while obscuring the business owner of the work.
7. I/O, memory and process/session headroom
SELECT d.name AS datafile, f.phyrds, f.phyblkrd, f.phywrts, f.phyblkwrt, f.readtim, f.writetimFROM v$filestat fJOIN v$datafile d ON d.file#=f.file#ORDER BY f.phyrds+f.phywrts DESC;
SELECT name,bytesFROM v$sgainfoORDER BY bytes DESC NULLS LAST;SELECT name,value,unitFROM v$pgastatWHERE name IN ( 'total PGA allocated', 'maximum PGA allocated', 'total PGA inuse', 'over allocation count', 'cache hit percentage')ORDER BY name;
SELECT resource_name, current_utilization, max_utilization, initial_allocation, limit_valueFROM v$resource_limitWHERE resource_name IN ( 'processes', 'sessions', 'transactions')ORDER BY resource_name;
V$FILESTAT and memory/resource views are
cumulative/state evidence. A large number is not automatically a
bottleneck. Snapshot them at T1/T2 and correlate deltas with
workload volume and OS/storage evidence.
8. Deliberately wrong: sort V$SYSTEM_EVENT by TIME_WAITED and declare the top row the root cause
Lifetime cumulative waits include yesterday's backups, startup work and normal workload. A top wait can be irrelevant to the current five-minute incident. The repair is the core diagnostic discipline of this chapter: capture bounded intervals, classify idle/non-idle waits, correlate with throughput and current sessions, and only then formulate a hypothesis.
9. Cleanup
DROP TABLE sh22_lock_case PURGE;
10. Production judgment
Start incidents with cheap live evidence. Restrict catalog
access: application users should not receive broad
SELECT ANY DICTIONARY merely for monitoring; use a
dedicated diagnostic role with narrowly required
V_$... grants or an approved catalog role/tool.
Preserve timestamps and query output externally because live
state disappears.
No optional pack, restart or COMPATIBLE change is
required for the core views used here. In RAC use
GV$ plus INST_ID; in a PDB understand
which rows/counters are container-filtered and use
CON_ID where supplied. Lesson 2 converts cumulative
views into bounded wait/time-model deltas.
Check your understanding
- What does ACTIVE mean in V$SESSION?
- Why can an INACTIVE session still block another session?
- Why should V$SQL lifetime buffer gets not be treated as current load automatically?
- What does V$RESOURCE_LIMIT prove?
- Why capture dynamic-view output externally during an incident?
Review the answers
It means the session is inside a database call; it can be on CPU or waiting.
It can hold locks from an uncommitted transaction while the client is idle between calls.
Cursor statistics are cumulative and can represent many healthy past executions; normalize and use interval deltas.
It shows configured/current/high-water utilization for resources such as processes/sessions, not application latency.
Sessions/cursors/memory state and cumulative counters can disappear/reset, so transient evidence needs timestamped preservation.
Authoritative references
- Dynamic Performance Views — V$/GV$ live-state model
- V$SESSION — session/wait/blocker fields
- V$SQL — cursor cumulative statistics
- V$LOCK — enqueue/lock state
- V$RESOURCE_LIMIT — resource utilization/headroom