夜间批处理变慢主因是Undo表空间被长事务卡死,ASH中大量ON CPU+空event+sys.undo$样本即为佐证;需查v$transaction中used_ublk>10000的阻塞事务,尤其status='INACTIVE'且username为空者,立即kill session,并通过DBA_TABLESPACE_USAGE_METRICS确认真实使用率是否超95%。

夜间批处理变慢,ASH里看不到业务SQL、全是ON CPU + 空event + sys.undo$递归调用,基本可断定是Undo表空间被长事务卡死,不是SQL本身慢。
查v$active_session_history里ON CPU + 空event的样本分布
批处理作业变慢时,ASH中往往不出现真实业务SQL,而是大量session_state = 'ON CPU'、event为空、sql_id = '0000000000000000'或sql_text LIKE '%sys.undo$%'的样本。这不是采样丢失,而是Oracle把Undo段分配、回滚段扩展等逻辑压进了CPU路径。
- 必须用动态时间窗口:
SAMPLE_TIME > SYSDATE - INTERVAL '10' MINUTE(别写死时间字符串) - RAC环境务必用
gv$active_session_history,否则只看到当前节点 - 重点过滤:
program含J000、BatchDelete、DBMS_SCHEDULER的记录——它们大概率是未提交的JOB在后台持续吃Undo - 别只盯
sql_id,要结合sql_opname IN ('INSERT','UPDATE','DELETE','DDL')确认真实压力源头
关联v$transaction找高used_ublk的阻塞事务
ASH只能反映瞬时状态;真正拖垮Undo空间的,往往是已断开但未清理的INACTIVE会话,或长时间未提交的JOB进程。它们在ASH里可能只留下几条样本,却持续占用used_ublk,导致新事务无法分配空间。
- 立刻执行:
SELECT s.sid, s.serial#, s.username, s.program, s.status, t.used_ublk, t.start_time FROM v$session s JOIN v$transaction t ON s.taddr = t.addr WHERE t.used_ublk > 10000 ORDER BY t.used_ublk DESC -
used_ublk单位是数据库块(默认8KB),>10000 ≈ >80MB,属高风险阈值 - 特别注意
status = 'INACTIVE'且username为空的记录——这通常是客户端异常断开后残留的事务,必须人工ALTER SYSTEM KILL SESSION 'sid,serial#' - 若
program为oracle@host且module含DBMS_JOB或DBMS_SCHEDULER,优先检查该JOB是否设置了COMMIT或ROLLBACK逻辑
验证DBA_TABLESPACE_USAGE_METRICS是否真满
很多人看DBA_FREE_SPACE发现还有几百MB就以为够用,结果还是报ORA-30036。这是因为Undo段需要连续空间,且受UNDO_RETENTION和未提交事务拖累。DBA_FREE_SPACE的“空闲”只是逻辑碎片,不是可用段空间。
- 查真实使用率:
SELECT tablespace_name, used_percent FROM DBA_TABLESPACE_USAGE_METRICS WHERE tablespace_name = (SELECT value FROM v$parameter WHERE name = 'undo_tablespace') - 若
used_percent> 95%,且v$transaction中存在多个used_ublk > 5000的事务,说明Undo空间已被实质性挤占 - 此时扩容Undo表空间无效——必须先清理长事务,再考虑调整
UNDO_RETENTION或启用AUTOEXTEND
最易被忽略的是:夜间作业变慢往往不是某条SQL突然变差,而是Undo资源被上游未提交的JOB悄悄锁死,下游所有DML被迫排队等待分配回滚段。这种瓶颈在ASH里不表现为等待事件,而表现为“不该有的CPU消耗”,必须跳出event思维,盯住used_ublk和sql_opname组合。


















