ASH不能直接查表锁状态,因为它仅每秒采样活跃会话的等待瞬间,不记录持锁者、锁对象及实时阻塞关系;查表锁必须关联V$LOCKED_OBJECT与V$SESSION。
ash 不能直接查表锁状态,它只记录“正在等”的瞬间;真要查谁锁了谁、锁了什么表,得靠 v$locked_object 和 v$session 关联查。
为什么不能只依赖 ASH 查表锁
ASH(V$ACTIVE_SESSION_HISTORY)每秒采样一次活跃会话,但只保留约1小时内存数据,且采样点是“等待发生时”的快照——它可能捕获到一个会话在等 enq: TX - row lock contention,但根本看不到谁持锁、锁在哪张表、甚至持锁会话可能已提交退出。
更关键的是:V$ACTIVE_SESSION_HISTORY 不包含 blocking_session 字段在早期版本(12c之前),而 final_blocking_session 在12c+才稳定可用;即使有,它也只反映采样那一刻的阻塞链,不是实时锁关系。
查表锁必须用 V$LOCKED_OBJECT + V$SESSION
真正能定位“哪张表被谁锁、持锁会话在执行什么SQL”的组合是 V$LOCKED_OBJECT 和 V$SESSION。常见误操作是只查 V$LOCK 或漏关联 DBA_OBJECTS 导致看不到表名。
- 先确认对象是否被锁:
SELECT lo.session_id, o.object_name, o.owner, s.osuser, s.machine, s.logon_time FROM v$locked_object lo JOIN dba_objects o ON lo.object_id = o.object_id JOIN v$session s ON lo.session_id = s.sid WHERE o.object_name = 'YOUR_TABLE_NAME';
- 若想看所有被锁的表(不限定表名),去掉
WHERE条件即可,但建议加AND o.object_type = 'TABLE'过滤掉索引、LOB等非表对象 -
V$LOCKED_OBJECT中的session_id是持有锁的会话ID,不是等待方;别和V$SESSION.BLOCKING_SESSION混淆 - 如果查不到结果,不代表没锁——可能是 DDL 锁(如
ALTER TABLE执行中),这时得查DBA_DDL_LOCKS
ASH 可用于辅助判断并发写压力是否异常
虽然 ASH 不直接显示锁,但它能暴露高并发写引发的争用模式,比如大量会话卡在 enq: TX - row lock contention 或 enq: TM - contention,这时说明写热点真实存在。
- 查最近1分钟的锁相关等待:
SELECT event, COUNT(*) cnt, session_id, blocking_session, final_blocking_session FROM v$active_session_history WHERE sample_time > SYSDATE - 1/1440 AND event LIKE 'enq: %' GROUP BY event, session_id, blocking_session, final_blocking_session ORDER BY cnt DESC;
- 注意:
blocking_session为空但final_blocking_session有值,说明存在级联阻塞(A→B→C),需顺藤摸瓜查 C 的V$SESSION状态 - 如果
event是enq: TX - row lock contention,但blocking_session总为空,大概率是硬解析争用(游标共享锁 S vs 排他锁 X),不是业务行锁,得转查V$SQL和V$SESSION的sql_id和prev_sql_addr
kill session 前务必确认 SQL 影响范围
查到持锁会话后,别急着 ALTER SYSTEM KILL SESSION。先看它在跑什么:
- 查当前执行 SQL:
SELECT sql_id, sql_text FROM v$session s JOIN v$sqlarea a ON s.sql_id = a.sql_id WHERE s.sid = &sid;
- 查上一条执行 SQL(常更准,因当前 SQL 可能已结束):
SELECT prev_sql_addr, prev_hash_value FROM v$session WHERE sid = &sid;
再用该地址去V$SQLAREA查原文 - 如果
sql_text含INSERT INTO ... SELECT或大事务更新,kill 可能触发长回滚,反而延长阻塞时间 -
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE比不加IMMEDIATE更快释放资源,但仍有风险;生产环境建议先ALTER SYSTEM DISCONNECT SESSION尝试优雅断开
最易被忽略的一点:V$LOCKED_OBJECT 不包含 DDL 锁信息,而 DDL 锁(如 CREATE INDEX、TRUNCATE)同样会阻塞 DML,且持续时间可能很长。遇到“查不到锁但表就是不能写”,第一反应应是查 DBA_DDL_LOCKS,而不是反复刷 V$LOCKED_OBJECT。











