ASH每秒采样活跃会话,AWR每小时聚合采样,瞬时锁(如14:07持锁4分钟)易被AWR快照遗漏;ASH可区分TX锁mode=4/6,AWR仅统一归类为enq: TX - row lock contention。

ASH报告里看到的enq: TX - row lock contention,AWR里却没出现
因为ASH和AWR根本不是同一套采样逻辑,不是“谁更准”,而是“谁在什么时间、以什么方式记了什么”。ASH每秒抓一次活跃会话,只存内存、只留约1小时;AWR每小时从ASH里抽一次样,再存到磁盘,默认保留8天。你查的那5分钟锁问题,如果发生在AWR两次快照中间(比如14:23),它大概率不会被AWR捕获——AWR只会记录14:00和15:00两个时间点的聚合值,中间的尖刺直接被平均掉了。
常见错误现象:enq: TX - row lock contention在ASH里高频出现(>20次/5分钟),但在AWR的Top 5 Timed Events里排不进前五,甚至压根不显示。
- 别急着怀疑权限或配置,先确认时间窗口:ASH报告必须限定
SAMPLE_TIME > SYSDATE - 5/1440,否则默认扫全内存ASH buffer(约1小时),可能因权限不足报ORA-00942 - AWR报告中该事件占比低,不代表没发生,只说明它没持续到整点快照时刻——锁可能在14:07持有了4分钟,14:11就释放了,但14:00和15:00两个快照都“错过”了
- 若需长期追踪这类瞬时锁,得用
DBA_HIST_ACTIVE_SESS_HISTORY(即AWR归档的ASH),但它依赖AWR采样频率,仍不如实时查gv$active_session_history可靠
为什么ASH显示final_blocking_session=0,AWR里却显示blocking_session有值
这是RAC环境下最典型的视图错位。blocking_session字段只存在于v$session和DBA_HIST_ACTIVE_SESS_HISTORY(AWR归档版ASH),它只反映本实例内的阻塞链局部信息;而final_blocking_session是gv$active_session_history才有的字段,专为跨实例定位根因设计。
使用场景:你在实例1上查AWR,看到SQL等待被SID 123阻塞;但去查实例1的v$session,发现SID 123本身也在等——它其实在等实例2上的某个会话。这个“实例2的会话”就是final_blocking_session,而它的final_blocking_instance必须配合查,否则你连它在哪台机器上都不知道。
- 查
gv$active_session_history时,必须显式SELECTfinal_blocking_session和final_blocking_instance,不能只SELECT *——很多脚本漏掉这两列,导致误判 -
final_blocking_session = 0或NULL,基本可断定是根阻塞源,90%对应的是未提交的批处理语句,比如UPDATE /*+ PARALLEL */ ... WHERE batch_id = ? - AWR报告里的
Top Blocking Sessions章节,底层查的是DBA_HIST_ACTIVE_SESS_HISTORY,它没有final_blocking_*字段,所以天然无法还原RAC真实阻塞路径
ASH里p1raw='54580004',但AWR把这算成enq: TX - row lock contention
AWR不做事件细分,它只按event字符串归类。而enq: TX - row lock contention这个字符串,在底层实际覆盖了两种完全不同的机制:mode=6(真行锁)和mode=4(ITL争用或唯一键冲突)。ASH能通过p1raw后两位精准区分,AWR不能。
性能影响很关键:杀掉mode=4的等待者毫无意义——下一个会话立刻重试,还是报ORA-00001或继续等。但AWR报告里它和mode=6混在一起统计,容易误导你去kill错对象。
- 验证是否唯一键冲突:查
sql_id对应语句是否为INSERT INTO ... VALUES (),且CURRENT_OBJ#指向唯一索引所在表 - 验证是否ITL不足:看等待会话的
ROW_WAIT_BLOCK#是否高度集中(比如连续多行都是同一block号),同时v$segment_statistics中该表的ITL waits计数上升 - AWR的
Segments by Row Lock Waits章节其实也分不清mode,它只是把所有enq: TX%事件的CURRENT_OBJ#做频次统计,所以高亮的表未必是被锁的表,可能是唯一约束触发的级联更新目标
为什么ASH报告生成后,某些会话的SQL_ID在AWR里查不到
因为ASH采样的是“正在执行”的会话快照,哪怕SQL刚执行100ms就被采到,也会记下sql_id;但AWR只收录那些“完成执行”且满足阈值的SQL——默认要求elapsed_time > 5s或buffer_gets > 1000才会进DBA_HIST_SQLSTAT。短平快的锁等待SQL(比如单行UPDATE后立即卡住),很可能在ASH里高频出现,但在AWR SQL Statistics里完全隐身。
容易踩的坑:看到ASH里sql_id = '2xb71ufa5wmrh'反复出现,就去AWR里搜它,结果找不到执行计划。这不是数据丢了,是它根本没达到AWR的收录门槛。
- 要查这类短SQL的真实执行计划,得立刻查
v$sql_plan(还在共享池里)或gv$sql_plan(RAC环境) - 如果SQL已老化出共享池,只能靠
DBA_HIST_SQL_PLAN,但它依赖AWR采样,同样受5秒阈值限制 - 真正可靠的链路是:ASH →
sql_id→gv$session查prev_sql_id或sql_child_number→ 再反查v$sql获取绑定变量和实际执行计划
真实排查中,最常被忽略的是:ASH和AWR不是互为备份的关系,而是互补的观测层。你不能指望AWR告诉你“谁在14:07:23卡住了”,也不能靠ASH回答“过去一周哪条SQL逻辑读最高”。它们各自有不可替代的盲区,混用时必须清楚每一行数据背后的采样逻辑和生命周期。











