Oracle 11g中TM锁本身不直接导致更新延迟,真正拖慢DML的是其隐含的表级排他意图;当会话持TM锁未释放且被其他会话以REQUEST=6请求时,会阻塞DDL、TRUNCATE等操作,并引发enq: TM - contention等待事件。
oracle 11g中段级锁定(tm锁)本身不直接导致“更新延迟”,真正拖慢dml的是它背后隐含的**表级排他意图**——当会话持有tm锁且未及时释放,其他会话对同一对象的ddl、truncate、分区操作或某些特殊dml(如涉及位图索引、物化视图日志刷新)就会被阻塞。识别关键不是看“有没有tm锁”,而是看“谁在等、等什么、为什么还不放”。
查v$lock里TM锁是否处于BLOCK=1状态
TM锁(Table/Partition lock)本身是共享的,但一旦某会话因事务未提交、长查询未结束或异常中断而持续持有TM锁,并且该锁被其他会话请求为排他模式(如REQUEST=6),就可能触发阻塞链。重点不是锁存在,而是它是否成为BLOCKING源头:
- 运行
SELECT sid, type, id1, id2, lmode, request, block FROM v$lock WHERE type = 'TM',重点关注block = 1的行 -
id1是对象ID,用SELECT object_name, object_type FROM dba_objects WHERE object_id = <id1></id1>确认是不是业务核心表(如ORDERS、CUSTOMERS) - 若
lmode = 3(SX,Sub-Exclusive)且request = 0,说明该会话只是正常DML持有,问题不大;但若request = 6(X,Exclusive)且block = 1,大概率是有人在执行TRUNCATE TABLE或ALTER TABLE ... DROP PARTITION被卡住
结合v$session看等待事件是否为enq: TM - contention
单纯有TM锁不等于有问题,必须确认当前活跃会话是否真的在等它。Oracle 11g中,段级锁争用的典型等待事件是 enq: TM - contention,不是 enq: TX(那是行锁):
- 执行
SELECT sid, event, sql_id, blocking_session, seconds_in_wait FROM v$session WHERE event = 'enq: TM - contention' AND status = 'ACTIVE' - 若
blocking_session非空,顺着查该会话:SELECT sid, serial#, username, program, sql_id, prev_sql_id, status, event FROM v$session WHERE sid = <blocking_sid></blocking_sid> - 特别注意:如果阻塞会话的
event是SQL*Net message from client或长时间停留在db file sequential read,说明它可能已断开但事务未回滚(ghost session),需人工清理
验证是否由物化视图刷新或分区DDL引发
在11g中,enq: TM - contention 最常来自两类操作:物化视图刷新和分区表DDL。它们看似“读操作”,实则会申请强TM锁:
- 检查是否有后台作业正在跑
DBMS_MVIEW.REFRESH:查v$session_longops中opname LIKE '%refresh%',并确认其target_desc是否指向你的业务表 - 排查分区操作:运行
SELECT sql_text FROM v$sql WHERE sql_text LIKE '%TRUNCATE%PARTITION%' OR sql_text LIKE '%ALTER%TABLE%EXCHANGE%',再关联v$session看执行者 - 注意一个陷阱:即使你没主动执行DDL,某些ETL工具(如ODI、DataStage)或应用框架(如Hibernate SchemaUpdate)可能在启动时自动尝试
TRUNCATE或DROP/CREATE临时表,而这些表恰好与业务表同名或共用段
别忽略延迟段(Deferred Segment Creation)的副作用
11gR2+默认启用延迟段,新建表不分配物理空间,user_segments 为空。但这会导致某些元数据查询(如 DBA_SEGMENTS)在首次访问时触发隐式段创建,而该过程需要TM锁。如果你的巡检脚本频繁查 DBA_SEGMENTS,又恰逢大量新表被创建但尚未插入数据,就可能卡在段初始化上:
- 查
SELECT segment_name, segment_type FROM user_segments WHERE segment_name LIKE 'TMP%',确认是否存在大量空表占位 - 临时绕过:对已知空表手动预分配段,
ALTER TABLE tmp_log ALLOCATE EXTENT,避免后续查询触发争用 - 长期方案:在建表语句末尾显式加
SEGMENT CREATION IMMEDIATE,禁用延迟段(需确保COMPATIBLE >= 11.2.0)
真正难处理的不是锁本身,而是那些不写日志、不报错、只静静挂着的“半截事务”——比如应用连接池未正确关闭、JDBC设置 autoCommit=false 后忘了 commit 或 rollback,或者物化视图刷新中途失败却没清理锁状态。这类情况不会出现在AWR TOP SQL里,只能靠定时扫描 v$lock + v$session 关联分析才能揪出来。


















