ASH不保存SQL文本,只能通过sql_id关联v$sql或dba_hist_sqltext查询;定位DML操作应优先分析current_obj#、current_file#、current_block#及enq: TX事件。
ASH里查不到DML语句文本,别白费劲翻 sql_text
ash(active session history)不保存完整的sql文本,sql_id 能拿到,但想靠 v$active_session_history.sql_text 看到update/delete语句?不存在的。oracle只存 sql_id 和执行堆栈,文本得去 v$sql 或 dba_hist_sqltext 关联查——而且后者有保留时限,默认8天,还依赖awr快照是否捕获到该sql。
- 真要还原DML内容,优先查
dba_hist_active_sess_history+dba_hist_sqltext,注意sql_id可能因绑定变量/优化器路径变化而不同 - 如果目标是“谁在更新哪张表”,直接看
current_obj#和current_file#/current_block#更靠谱,它们指向被访问的对象和数据块 - 别在ASH里过滤
sql_text like '%UPDATE%',这条件永远不生效
定位频繁更新的表:盯紧 current_obj# + event 组合
行锁等待本质是会话卡在 enq: TX - row lock contention 事件上,而持有锁的会话往往正活跃在UPDATE/DELETE语句中。这时看 current_obj# 就能知道它正在操作哪张表(需关联 dba_objects.object_name)。
- 查最近1小时被最多TX争用的表:
SELECT o.object_name, COUNT(*) cnt FROM dba_hist_active_sess_history h JOIN dba_objects o ON h.current_obj# = o.object_id WHERE h.event = 'enq: TX - row lock contention' AND h.sample_time > SYSDATE - 1/24 GROUP BY o.object_name ORDER BY cnt DESC;
-
current_obj#为0表示没访问具体对象(比如解析、递归调用),不是所有UPDATE都会填这个字段;真正写入前可能先走逻辑读,所以也得看event是db file sequential read还是enq: TX - 注意区分“高频更新”和“长事务更新”:前者
session_id频繁出现,后者单个会话在ASH里持续多条记录
查具体哪一行被锁:current_file# 和 current_block# 是唯一线索
ASH里没有ROWID,但有 current_file# 和 current_block#,结合对象段信息,能定位到具体数据块。再用 dbms_rowid.rowid_create 构造伪ROWID,就能查出块里有哪些行被频繁修改或锁定。
- 先找出热点块:
SELECT current_file#, current_block#, COUNT(*) cnt FROM dba_hist_active_sess_history WHERE event = 'enq: TX - row lock contention' AND sample_time > SYSDATE - 1/24 GROUP BY current_file#, current_block# ORDER BY cnt DESC;
- 用结果反查行:
SELECT rowid, t.* FROM your_table t WHERE dbms_rowid.rowid_relative_fno(rowid) = &file_id AND dbms_rowid.rowid_block_number(rowid) = &block_id;
(注意:仅适用于非IOT、非分区表的常规堆表) - 如果表是分区表,
current_obj#指向分区对象而非基表,得先查dba_tab_partitions确认分区名
别漏掉“隐式锁”:未提交事务 + SELECT FOR UPDATE 也会进ASH
SELECT ... FOR UPDATE 不是DML,但它申请TX锁,一旦没提交,后续UPDATE就会等在 enq: TX 上。这类会话在ASH里 sql_opname 是 SELECT,但 event 是锁等待,容易误判成纯查询问题。
- 查疑似“假查询真锁表”的会话:
SELECT sql_id, sql_opname, event, blocking_session, sample_time FROM dba_hist_active_sess_history WHERE sql_opname = 'SELECT' AND event = 'enq: TX - row lock contention' AND sample_time > SYSDATE - 1/24;
- 这类问题常出现在应用层没正确关闭事务,或者用了连接池但没显式COMMIT/ROLLBACK
- ASH里看不到
blocking_session的完整链路(比如A锁B、B锁C),只能看到直接阻塞者;要追根得用v$lock+v$session实时抓
ASH是采样数据,1秒一次,短于1秒的锁争用大概率被跳过;真要精确定位某次超时,得配合应用日志里的SQL时间戳,再反查那一秒附近的ASH记录——这点最容易被忽略。










