ASH无法直接查触发器名,只能通过行为指纹识别:如latch: row cache objects、空sql_id、高频ON CPU等;需结合v$SQL.program_id与DBA_OBJECTS交叉验证溯源,11g需人工比对命名惯例。
ASH里查不到触发器名,但能抓到它留下的“行为指纹”
ash不记录触发器本身的名字,因为v$active_session_history只保存采样瞬间的前台会话状态,而触发器执行属于递归调用,堆栈不会展开。你看到的sql_id永远是外层dml(比如insert into orders),不是触发器里的select或update。关键不是找“trigger”,而是识别它引发的异常模式。
常见行为指纹包括:
-
event = 'latch: row cache objects'+p1在2/6/7/10之间(对应dc_tables、dc_users等字典缓存)→ 触发器里查了user_tables这类字典表 -
sql_id = '00000000000000000000000000000000'+event IN ('library cache lock', 'latch: shared pool')→ 触发器内SQL走硬解析 -
current_obj# <= 0或为空 + 高频ON CPU样本 → PRAGMA AUTONOMOUS_TRANSACTION频繁提交,导致短生命周期会话激增 -
event = 'enq: TX - row lock contention'+sql_id为空 +machine字段一致 → 触发器隐式更新了另一张表,引发行锁等待
怎么把空sql_id或00000000000000000000000000000000关联到具体触发器?
不能只查V$ACTIVE_SESSION_HISTORY。必须交叉验证三步:
第一步:按时间窗口提取可疑样本
SELECT sql_id, COUNT(*) cnt FROM v$active_session_history WHERE sample_time > SYSDATE - 1/1440 AND (sql_id IS NULL OR sql_id = '00000000000000000000000000000000') GROUP BY sql_id ORDER BY cnt DESC FETCH FIRST 5 ROWS ONLY;
第二步:查V$SQL反推调用者(仅12c+稳定支持)
SELECT program_id, program_line#, sql_text FROM v$sql WHERE sql_id = '<your_sql_id>';
若program_id > 0,说明该SQL由存储对象调用;第三步查DBA_OBJECTS确认类型:
SELECT object_name, object_type FROM dba_objects WHERE object_id = &program_id;
如果object_type = 'TRIGGER',基本坐实。11g用户只能靠sql_text里表名+命名惯例(如trg_orders_bri)人工比对。
为什么大批量INSERT变慢,ASH却只显示几条样本?
触发器逻辑复杂时,单次DML可能触发多次递归调用,但ASH每秒只采样一次,且默认只记录前台会话——后台进程(如ora_dbw0_*、ora_lgwr_*)的UNDO写入、索引分裂、日志刷盘动作不会出现在V$ACTIVE_SESSION_HISTORY里。结果就是:你看到的是“INSERT很快”,实际瓶颈卡在触发器引发的连锁反应上。
典型表现:
- 主DML的
sql_id样本稀疏,但ON CPU占比异常高(触发器PL/SQL解释执行开销) - 关联的递归SQL(如触发器里
UPDATE config_cache)出现db file sequential read高频采样 -
v$session_event中enq: US - contention或log file sync等待时间突增,但ASH里找不到对应前台会话
此时必须跳出ASH,立刻查:v$session_event实时等待、AWR聚合趋势、归档日志生成速率(v$log_history)。
容易被忽略的兼容性与采样盲区
12c之前版本的V$SQL.program_id不可靠,不能直接用于触发器溯源;V$ACTIVE_SESSION_HISTORY内存保留约1小时,重启即清空,查历史问题必须用DBA_HIST_ACTIVE_SESS_HISTORY,但它的采样粒度更粗(默认每10秒一次)。更隐蔽的是:如果触发器里用了DBMS_ALERT或UTL_HTTP这类外部调用,ASH只会记PL/SQL lock timer或SQL*Net message from dblink,根本看不出和触发器的关系——这时候得结合DBA_TRIGGERS禁用测试,或开10046 trace抓完整调用链。


















