必须用gv$active_session_history查跨节点锁,因v$active_session_history仅限本节点采样,无法捕获其他实例的持锁会话;final_blocking_session需配合final_blocking_instance才能准确定位根阻塞源。

必须用 gv$active_session_history 查,且要同时匹配 final_blocking_session 和 final_blocking_instance,否则跨节点锁冲突大概率漏掉——v$active_session_history 只能看到本节点样本,而真实持锁会话常在另一个实例上。
为什么只查 v$active_session_history 会错过跨节点锁
单实例下 blocking_session 指向本机 SID,但在 RAC 中,A 节点上的等待会话可能被 B 节点上的会话持锁阻塞。v$active_session_history 不跨实例聚合,你连上节点1执行查询,永远看不到节点2上那个没提交的事务。只有 gv$active_session_history 才把所有实例的 ASH 内存合并暴露出来。
常见错误包括:
- 用
v$active_session_history加blocking_instance = 2过滤——该视图根本没有blocking_instance字段,条件无效 - 查到
blocking_session = 1234就去节点1的v$session里找,结果发现该会话已断开或根本不存在 - 忽略
final_blocking_session,只看blocking_session,导致只看到中间跳板(比如 A→B→C),却漏掉真正的根阻塞源 C
final_blocking_session 和 final_blocking_instance 必须一起用
final_blocking_session 是 Oracle 12c+ 引入的字段,它穿透了 A→B→C 的级联链,直接指向最终持锁者;但它的值只有配合 final_blocking_instance 才有意义——因为那个 SID 可能在另一个节点上。
实操建议用这个查询快速定位:
抓取并分析 OpenClaw JSONL 会话日志,重建并回填代理记忆文件。适用于:(1) 模型切换后记忆不完整,(2) 验证记忆覆盖度,(3) 重建丢失记忆,(4) 通过 cron/heartbeat 自动同步每日记忆。支持简单提取及基于 LLM 的叙事摘要,并自动清理敏感信息。
SELECT sample_time, inst_id, session_id, final_blocking_instance, final_blocking_session, event, sql_id, current_obj# FROM gv$active_session_history WHERE sample_time > SYSDATE - 5/1440 AND event = 'enq: TX - row lock contention' AND final_blocking_session IS NOT NULL AND final_blocking_instance IS NOT NULL ORDER BY sample_time DESC;
关键点:
- 确认
final_blocking_instance对应的实例当前在线:SELECT instance_number FROM gv$instance WHERE inst_id = :final_blocking_instance - 若
final_blocking_session返回 0 或空,说明它是根阻塞源(比如一个未提交的批处理会话) - 别用
blocking_session做 JOIN 条件——它不稳定,final_*字段才是唯一可信锚点
验证持锁会话是否真在运行,不能只信 ASH 快照
ASH 是秒级采样,持锁时间若短于采样间隔(比如锁在 14:22:37.2 持有、14:22:37.8 释放),就可能刚好错过。所以从 gv$active_session_history 找到 final_blocking_instance = 2 和 final_blocking_session = 5678 后,必须立刻切到节点2执行:
SELECT sid, serial#, username, status, event, sql_id, logon_time, prev_sql_id FROM v$session WHERE sid = 5678 AND status = 'ACTIVE';
注意:
- 必须加
status = 'ACTIVE',排除僵尸会话残留 - 看
prev_sql_id是否和 ASH 里的sql_id一致——不一致说明该会话刚执行完一条语句,但事务仍开着 - 如果
event是SQL*Net message from client,大概率就是那个忘了COMMIT的应用连接
跨节点锁的典型特征:同一 current_obj# + 不同 inst_id 高频出现
真实跨节点行锁冲突不是孤立事件,而是多个节点上的会话反复争抢同一张表的同一组数据块。在 gv$active_session_history 中会表现为:
- 多个不同
inst_id的样本,current_obj#相同(比如都是 98765) -
sql_id高度集中(比如 90% 样本都是abc123xyz) - 等待事件全是
enq: TX - row lock contention,但blocking_session指向不同节点上的不同 SID
这时不要急着 kill,先查对象:SELECT owner, object_name FROM dba_objects WHERE object_id = 98765。如果这张表是订单主表或账户余额表,基本可锁定是业务并发控制粒度太粗,而非 SQL 本身有问题。

















