直接查v$locked_object和v$lock需关联dba_objects、dba_segments及dba_tablespaces才能准确定位dml锁定的表空间;仅查v$lock无法获知表空间信息,易误判影响范围。
直接查 v$locked_object 和 v$lock 就能定位到被 dml 锁住的段(通常是表或分区),但必须关联 dba_segments 或 dba_objects 才能落到具体表空间。光看锁不看段归属,容易误判锁影响范围。
查哪些段被 DML 锁定并归属到表空间
核心是把锁信息和段元数据对上。DML 锁(TM 类型)锁的是对象,而对象所属的段(segment)才属于某个表空间。不能只查 V$LOCK 的 ID1 就完事——它只是 OBJECT_ID,得再连一次 DBA_OBJECTS,再连 DBA_SEGMENTS 才能确认表空间。
推荐用这个查询:
SELECT
s.tablespace_name,
o.object_name,
o.object_type,
lo.session_id,
lo.locked_mode,
se.segment_type
FROM v$locked_object lo
JOIN dba_objects o ON lo.object_id = o.object_id
JOIN dba_segments se ON o.owner = se.owner AND o.object_name = se.segment_name
JOIN dba_tablespaces s ON se.tablespace_name = s.tablespace_name
WHERE o.object_type IN ('TABLE', 'TABLE PARTITION', 'INDEX')
ORDER BY s.tablespace_name, o.object_name;
-
lo.locked_mode值为 3 表示 Row-X(常见于 UPDATE/DELETE),6 表示 Exclusive(如 DDL 操作期间) - 如果
o.object_type是INDEX,也要关注——索引段和基表可能在不同表空间,锁会影响整个 DML 性能 - 没查到结果?先确认你有
SELECT ANY DICTIONARY权限,否则DBA_*视图不可见
为什么不能只靠 V$LOCK 查表空间
V$LOCK 里的 ID1 字段对 TM 锁来说确实是 OBJECT_ID,但它不包含段位置信息;V$LOCK 本身也不存表空间字段。硬要从 V$LOCK 出发,你得额外 JOIN 三次:DBA_OBJECTS → DBA_SEGMENTS → DBA_TABLESPACES,比直接从 V$LOCKED_OBJECT 起点更绕、更容易漏条件。
常见错误写法:
SELECT * FROM V$LOCK WHERE TYPE = 'TM'; -- ❌ 只看到 SID 和 ID1,不知道在哪个表空间
- 这种查询只能告诉你“有 TM 锁”,但无法回答“这个锁影响了哪个表空间的资源”
- 如果业务集中在
USERS表空间,而锁实际发生在INDEX_TBS,只看V$LOCK会误导排查方向 -
V$LOCKED_OBJECT已经过滤掉非活动锁,比V$LOCK更聚焦真实阻塞源
区分 DML 锁和事务未提交导致的假锁定
Oracle 的 DML 锁(TM)和行级锁(TX)常一起出现,但只有 TM 锁会阻止其他会话对整张表做 DDL 或某些 DML。真正卡住业务的往往是 TX 锁未释放 + 对应的 TM 锁持续存在。
检查是否真被锁死,而不是事务挂起:
SELECT s.sid, s.serial#, s.status, s.sql_id, s.prev_sql_id, s.event FROM v$session s WHERE s.sid IN (SELECT session_id FROM v$locked_object);
- 如果
status是INACTIVE且event是SQL*Net message from client,大概率是应用没提交/回滚,连接还挂着 - 如果
sql_id对应的 SQL 是长事务(比如大批量 UPDATE),别急着 kill,先看它执行了多久(查V$SESSION_LONGOPS) -
prev_sql_id有时比sql_id更准——当前会话可能正等网络响应,真正干活的 SQL 已结束
最易忽略的一点:DBA_SEGMENTS 中的 segment_name 和 DBA_OBJECTS 中的 object_name 并不总是一一对应(比如 IOT 的 overflow segment),查锁时优先以 OBJECT_ID 关联,别依赖名字匹配。











