ASH不直接显示触发器名,因其执行堆栈不展开于V$ACTIVE_SESSION_HISTORY中;需通过高频row cache latch争抢、空sql_id配合library cache等待、或program_id关联DBA_OBJECTS等行为指纹交叉验证定位。
ash 本身不直接标记“这是触发器”,但能暴露触发器引发的典型症状——比如高频递归调用、硬解析、row cache latch争抢或隐式锁等待。关键不是找“trigger”字样,而是识别它留下的行为指纹。
查 V$ACTIVE_SESSION_HISTORY 时为什么看不到触发器名?
因为 V$ACTIVE_SESSION_HISTORY 记录的是会话在采样瞬间的执行状态,而触发器代码属于被调用的 PL/SQL 单元,其执行堆栈不会完整展开到 ASH 行中。你看到的 sql_id 通常是外层 DML(如 INSERT INTO t1),不是触发器本身的 SQL。
- 触发器内执行的
SELECT或UPDATE若走硬解析,会体现在sql_id为00000000000000000000000000000000或空值,同时event为latch: shared pool或library cache lock - 触发器若访问字典表(如
SELECT COUNT(*) FROM user_tables),会高频触发row cache objects等待,且current_obj#常为 0 或负数 - 触发器中含
PRAGMA AUTONOMOUS_TRANSACTION并频繁提交,会在 ASH 中表现为大量短生命周期的ON CPU+log file sync组合
如何从 sql_id 关联到触发器逻辑?
不能只查 V$ACTIVE_SESSION_HISTORY,必须交叉验证:
- 先按时间窗口提取高频
sql_id:SELECT sql_id, COUNT(*) FROM v$active_session_history WHERE sample_time > SYSDATE - 1/1440 GROUP BY sql_id ORDER BY 2 DESC FETCH FIRST 5 ROWS ONLY - 对每个可疑
sql_id,查V$SQL的program_id和program_line#:SELECT program_id, program_line#, sql_text FROM v$sql WHERE sql_id = 'xxx';若program_id > 0,说明该 SQL 是由某个存储对象(含触发器)调用的 - 再查
DBA_OBJECTS反推:SELECT object_name, object_type FROM dba_objects WHERE object_id = &program_id;若object_type = 'TRIGGER',基本坐实 - 注意:12c+ 才支持
V$SQL.program_id稳定记录触发器 ID;11g 只能靠sql_text中的表名 + 上下文 + 触发器命名惯例(如trg_t1_bri)人工比对
触发器引发的典型 ASH 模式有哪些?
以下组合出现频次高,基本可判定是触发器问题:
-
event = 'latch: row cache objects'+p1text = 'cache id'+p1 IN (2,6,7,10)(对应 dc_tables, dc_users, dc_segments 等)→ 触发器里查了数据字典 -
event = 'enq: TX - row lock contention'+sql_id为空 +machine字段显示应用服务器名一致 → 触发器内隐式更新了另一张表,且未加索引导致锁升级 -
session_state = 'ON CPU'+sql_opname = 'PL/SQL EXECUTE'+program含oraagent或oracle@... (J00)→ 触发器含复杂循环或游标遍历 - 同一
session_id在 1 分钟内反复出现cursor: pin S wait on X+blocking_session为自身 → 触发器递归调用自身(如 A 表触发器改 B 表,B 表触发器又改 A 表)
为什么 DBA_HIST_ACTIVE_SESS_HISTORY 有时比 V$ACTIVE_SESSION_HISTORY 更有用?
因为触发器问题常具周期性(如每小时跑一次批处理),而 V$ACTIVE_SESSION_HISTORY 内存只保留约 1 小时数据,容易覆盖。这时得依赖磁盘归档:
-
DBA_HIST_ACTIVE_SESS_HISTORY依赖 AWR 快照,默认每小时 1 次,但采样粒度是 10 秒 —— 虽不如实时视图细,却能跨时段比对 - 查法:
SELECT sample_time, event, sql_id, current_obj#, program FROM dba_hist_active_sess_history WHERE sample_time BETWEEN TIMESTAMP '2026-04-28 14:00:00' AND TIMESTAMP '2026-04-28 15:00:00' AND event LIKE '%row cache%' ORDER BY sample_time - 重点看
current_obj#是否稳定指向某张业务表(比如一直是 12345),再结合DBA_TRIGGERS查table_obj# = 12345的触发器,缩小范围 - 注意:
DBA_HIST_ACTIVE_SESS_HISTORY中sql_id可能为 NULL,但sql_plan_hash_value和top_level_sql_id仍可辅助定位外层语句
真正难的不是查出触发器,而是确认它是否在非预期路径下被调用——比如一个本该只在 UI 提交时触发的 BEFORE INSERT,结果被批量脚本绕过约束直接插入,导致触发器在高并发下成为瓶颈。这种场景下,V$SESSION 的 sql_id 和 prev_sql_id 对比,比 ASH 更管用。



















