
好的,我们来深入解析 Oracle 数据库中的 enq: TW - contention 等待事件。这个事件与表空间的空间管理密切相关,通常在高并发执行 DML 操作(特别是插入 INSERT)时出现,是影响数据库性能的一个重要因素。
1. 什么是 enq: TW - contention 等待事件?
- 本质: 它表示一个会话正在等待获取
TW(TableSpace Management / Transaction Table)` Enqueue (队列锁)。这个锁用于协调对表空间空间管理数据结构(主要是位图块)的访问,确保空间分配和释放操作的序列化和一致性。 - 名字解析:
enq:: 表示这是一个 Enqueue 等待事件。TW: Enqueue 的类型标识符。T代表TableSpace Management或Transaction Table(在空间管理的上下文中,更侧重TableSpace Management),W代表模式,通常是Wait或Write模式,表示会话需要以独占或修改的方式获取该锁。contention: 表示发生了争用,即多个会话同时尝试获取同一个TWEnqueue,导致部分会话必须等待。
- 核心特征:
- 保护空间管理元数据:
TWEnqueue 主要保护的是表空间空间管理元数据的完整性。对于本地管理的表空间 (Locally Managed Tablespaces - LMT),这指的是位图块 (Bitmap Blocks);对于字典管理的表空间 (Dictionary-Managed Tablespaces - DMT),这指的是数据字典中的UET$(Used Extents) 和FET$(Free Extents) 表(但 DMT 已基本淘汰,LMT 是默认和推荐)。 - 序列化访问: 当会话需要执行空间操作(如分配新区、释放区、合并空闲区)时,必须先获取相应的
TWEnqueue(通常对应特定的表空间和文件)才能安全地修改位图块。一次只能有一个会话持有特定范围的TWEnqueue 进行修改。 - 高并发 DML 的瓶颈: 在高并发执行
INSERT(需要分配新区/新块)或DELETE/UPDATE(可能导致块内空间回收或区释放)的操作时,对空间管理元数据的争用会成为显著瓶颈。 - ASSM 的影响: 自动段空间管理 (Automatic Segment Space Management - ASSM /
SEGMENT SPACE MANAGEMENT AUTO) 是 LMT 的扩展,它使用更复杂的三级位图结构(L1, L2, L3) 来管理段内的块空间。虽然 ASSM 提高了空间利用率,但在极端高并发插入场景下,对段头块 (Segment Header) 和位图块 (Bitmap Blocks) 的争用(包括TWEnqueue 争用)可能会加剧。
- 保护空间管理元数据:
- 等待参数:
P1: Enqueue 的名称和模式。格式为name|mode。对于TW,name是TW,mode通常是6(表示独占模式eXclusive- X),有时也可能是4(共享模式Share- S)或其他模式,但修改空间元数据通常需要 X 模式。P2: Enqueue 标识符 1 (id1)。对于TWEnqueue,id1通常是 表空间号 (TS#) 和 相对文件号 (RFN) 的组合(具体格式可能因版本而异,但通常包含表空间信息)。P3: Enqueue 标识符 2 (id2)。对于TWEnqueue,id2通常是 位图块号 (Block#) 或与特定空间管理操作相关的标识符。它标识了 Enqueue 保护的具体资源(通常是位图块)。
2. 产生的过程
当一个会话执行的操作需要修改表空间的空间管理信息时(以 LMT + ASSM 为例):
- 触发空间操作: 会话执行一个 DML 语句(通常是
INSERT),需要向一个段(表或索引)中插入新数据。 - 空间需求:
- 当前使用的块没有足够空间 (
INSERT最常见原因)。 - 需要分配一个新区 (
Extent)。 - 需要释放一个区 (
DELETE大量数据后)。
- 当前使用的块没有足够空间 (
- 定位空间管理元数据: Oracle 确定需要访问和修改哪个(些)位图块(L1, L2, L3)来满足空间请求。这些位图块位于表空间的数据文件中。
- 请求
TWEnqueue: 会话尝试以独占模式 (X) 获取保护该特定位图块(或位图块范围)的TWEnqueue。id1标识了表空间/文件,id2标识了具体的位图块。 - 检查锁可用性:
- 可用: 如果没有其他会话持有该
TWEnqueue 的冲突模式锁(X 模式与任何其他模式都冲突),会话成功获取锁,立即修改位图块,执行空间分配/回收操作,然后释放TWEnqueue。不会产生等待。 - 不可用(争用): 如果另一个会话已经持有该
TWEnqueue 的冲突模式锁(通常是另一个会话也在修改同一个位图块),当前会话无法立即获取锁。
- 可用: 如果没有其他会话持有该
- 进入等待: 会话进入
enq: TW - contention等待状态,并排队等待该TWEnqueue。 - 持有者释放: 持有该
TWEnqueue 的会话完成其空间管理操作(修改位图块)后,释放锁。 - 唤醒等待者: 等待队列中的下一个会话(按排队顺序)被唤醒,获得
TWEnqueue 锁。 - 执行空间操作: 该会话修改位图块,完成其空间分配或回收操作。
- 释放锁并继续: 会话释放
TWEnqueue,继续执行其 DML 操作(如实际插入数据到新分配的块中)。 - 递归空间操作: 有时,空间操作本身(如扩展段)可能需要递归地分配空间(例如,为位图块本身或回滚段/撤销段分配空间),这可能导致更深层次的
TW或其他 Enqueue 争用。
3. 哪些场景会触发 enq: TW - contention
主要发生在高并发执行需要操作空间管理元数据的 DML 时,尤其是:
- 高并发
INSERT: 这是最常见、最典型的场景。大量会话同时向同一个表或少数几个热表插入数据。- 当插入导致块填满时,需要分配新块。
- 当插入导致区填满时,需要分配新区。
- ASSM 表空间下,频繁访问 L1/L2/L3 位图块寻找空闲块/空间。
- 高并发
DELETE或UPDATE(导致行迁移):- 大量删除数据可能导致释放区(如果整个区变空),需要修改位图块标记区为空闲。
UPDATE导致行增长并迁移到新块,也可能触发新块分配。
- 创建/重建/截断索引: 这些操作需要为索引段分配大量的新区。
- 批量数据加载 (
SQL*Loader,INSERT /*+ APPEND */): 即使单个会话,如果操作涉及大量、快速的空间分配,也可能在递归空间操作中遇到TW争用(例如,为位图块本身或撤销段分配空间)。 - 段维护操作 (
ALTER TABLE ... MOVE,ALTER INDEX ... REBUILD): 重建表或索引需要分配新空间并释放旧空间。 - 操作使用
AUTOEXTEND且频繁扩展的数据文件: 虽然文件扩展本身可能涉及其他等待,但文件扩展后为新空间分配位图块也可能涉及TW。
4. 可能的原因
enq: TW - contention 的出现通常意味着空间管理操作成为了高并发 DML 的瓶颈。主要原因包括:
- A. 高并发 DML 操作热点:
- 针对单个表/索引的高并发
INSERT: 这是 最根本、最常见 的原因。大量会话同时向同一个对象插入数据,争相修改其对应的位图块(特别是段头块和L1/L2位图块)。 - 针对少数几个热对象的高并发 DML: 争用集中在这些对象的空间管理元数据上。
- 针对单个表/索引的高并发
- B. 空间管理效率低下 (对象级配置):
- 过小的区大小 (
INITIAL,NEXT): 区大小设置得太小(如默认的64K或1M),意味着需要更频繁地分配新区。每次新区分配都需要获取TWEnqueue 并修改位图块。增大区大小是缓解TW争用的关键手段之一。 - 高
PCTFREE设置:PCTFREE设置过高(如 40%)意味着每个块预留更多空间给未来更新,导致块更快被“填满”(达到PCTFREE限制),从而更频繁地需要分配新块。对于插入为主的表,适当降低PCTFREE(如 10%)可以延缓新块分配。 FREELISTS/FREELIST GROUPS不足 (非ASSM): 在手动段空间管理 (MANUAL) 的表空间中,FREELISTS数量不足会导致多个会话争用同一个FREELIST链来寻找空闲块,进而加剧对段头块(包含FREELIST)的争用(表现为buffer busy waits或间接导致TW)。但 ASSM 是主流。
- 过小的区大小 (
- C. ASSM 位图块争用:
- 位图块成为热点: 在 ASSM 下,L1 (段头块)、L2、L3 位图块本身也可能成为争用点。高并发插入时,多个会话争相查询和更新同一个位图块(特别是 L1/L2)以寻找空闲块或标记块的使用情况。
- 位图块数量不足/分布集中: 对于非常大的段或插入率极高的段,如果位图块数量相对较少或物理上集中,争用会更严重。
- D. 递归空间操作:
- 撤销段/回滚段扩展: DML 操作本身需要生成撤销记录。如果撤销表空间 (
UNDO) 配置不当(如区太小、表空间不足),导致在 DML 过程中需要扩展撤销段或分配新的撤销块,这些递归的空间操作也会需要获取TWEnqueue,加剧了原始 DML 会话的TW争用。 - 位图块自身的空间分配: 当需要为空间管理元数据(位图块本身)分配新块或新区时,也会触发更深层次的
TW请求。
- 撤销段/回滚段扩展: DML 操作本身需要生成撤销记录。如果撤销表空间 (
- E. 表空间/存储配置:
- 统一区大小 (
UNIFORM SIZE) 设置过小: 虽然统一区大小管理简单,但如果设置太小(如 1M),在高插入率下会导致非常频繁的区分配和TW争用。考虑增大UNIFORM SIZE或使用AUTOALLOCATE。 AUTOALLOCATE与初始小扩展:AUTOALLOCATE表空间初始分配很小的区(如 64K),随着段增长逐渐分配更大的区。在段快速增长初期,频繁的小区分配也可能导致TW争用。_use_realfree_heap参数影响行为。- 过多小文件或碎片: 虽然 LMT 减少了碎片,但表空间包含大量小文件或存在某种程度的空间碎片,可能增加空间管理的复杂性(非主要原因)。
- 统一区大小 (
- F. 数据库参数与版本:
_use_realfree_heap: 这个隐含参数控制 LMT 空闲空间管理算法。在 11g 及以后,默认通常为TRUE,使用更高效的“Real Free Heap”管理,能减少TW争用。如果设置为FALSE(旧行为),可能更容易发生争用。通常不建议修改。- 较旧版本: 老版本的 Oracle 在空间管理效率和并发性方面可能不如新版本优化。
5. 详细排查过程
排查 enq: TW - contention 的核心是:定位热点对象 -> 分析其空间配置和 DML 模式 -> 针对性优化。
步骤 1: 确认问题与范围
- 识别 Top Wait Event: 查看 AWR/ASH 报告 (
awrrpt.sql,ashtop.sql)。确认enq: TW - contention是否在系统级别或特定时间段是主要等待事件。记录其Total Wait Time (s)和Avg Wait (ms)。 - 确定影响范围: 是整个数据库负载高峰时出现?还是特定模块/特定表操作时出现?使用 ASH 报告 (
ashrpt.sql) 或查询gv$active_session_history/dba_hist_active_sess_history,按sql_id,module,action,user_id,current_obj#等维度聚合等待事件和时间。特别关注sql_id是否是INSERT语句。 - 关联负载类型: 检查 AWR 报告的 “Load Profile” 部分。高
Executions, 高Transactions, 特别是高Rows per Sort可能暗示批量插入。高Physical Writes也与插入相关。
步骤 2: 定位热点对象和 SQL
- ASH 分析 (最有效):
-- 查找经历 TW 等待最多的对象和 SQL SELECT ash.sql_id, ash.sql_plan_operation, ash.sql_plan_options, -- 执行计划操作 (通常是 TABLE ACCESS INSERT) o.owner, o.object_name, o.object_type, o.subobject_name, -- 对象信息 COUNT(*) AS total_waits, SUM(ash.time_waited)/1000 AS total_wait_sec, AVG(ash.time_waited)/1000 AS avg_wait_ms FROM dba_hist_active_sess_history ash -- 或用 gv$active_session_history 查实时 JOIN dba_objects o ON (ash.current_obj# = o.object_id) WHERE ash.event = 'enq: TW - contention' AND ash.sample_time BETWEEN ... AND ... -- 指定问题时间段 GROUP BY ash.sql_id, ash.sql_plan_operation, ash.sql_plan_options, o.owner, o.object_name, o.object_type, o.subobject_name ORDER BY total_waits DESC, total_wait_sec DESC;- 这会直接告诉你哪个对象(
object_name,可能是表或索引)和哪个 SQL (sql_id) 导致了最多的TW等待。 sql_plan_operation为TABLE ACCESS+INSERT或INDEX+INSERT是典型。subobject_name指示是否是分区。
- 这会直接告诉你哪个对象(
- 关联 SQL 文本: 使用找到的
sql_id,查询v$sqltext或dba_hist_sqltext获取完整的 SQL 语句。确认是否是插入操作。 - 实时会话查询 (
v$session/v$session_wait):SELECT s.sid, s.serial#, s.username, s.program, s.module, s.action, s.sql_id, s.prev_sql_id, -- 当前和前一个 SQL w.event, w.state, w.wait_time, w.seconds_in_wait, w.p1, w.p2, w.p3, -- Enqueue 参数 o.owner, o.object_name, o.object_type -- 当前对象 (可能不准确) FROM v$session s JOIN v$session_wait w ON (s.sid = w.sid) LEFT JOIN dba_objects o ON (s.row_wait_obj# = o.object_id) -- row_wait_obj# 有时指示相关对象 WHERE w.event = 'enq: TW - contention' AND s.status = 'ACTIVE';- 观察
sql_id,prev_sql_id关联 SQL。 - 解析
P1,P2,P3:P1='name|mode'(e.g.,'TW|6')P2=id1(通常包含TS#表空间号)P3=id2(通常指定位图块号)
- 使用
P2 (id1)查询表空间:SELECT ts#, name FROM v$tablespace WHERE ts# = &extracted_ts#; -- 从 id1 提取 TS#
- 观察
步骤 3: 分析热点对象的空间配置
对步骤 2 定位到的热点表(及关联索引)进行详细分析:
- 查询段信息 (
DBA_SEGMENTS):SELECT owner, segment_name, segment_type, partition_name, tablespace_name, header_file, header_block, -- 段头位置 bytes/1024/1024 AS size_mb, blocks, extents, initial_extent/1024 AS init_kb, next_extent/1024 AS next_kb, -- 区大小 pct_increase, -- 通常为 0 freelists, freelist_groups -- 仅对 MSSM 有意义 FROM dba_segments WHERE owner = '&owner' AND segment_name = '&segment_name';- 核心关注
initial_extent,next_extent: 是否过小(如 <= 1MB)?这是TW争用的关键诱因。 extents: 如果区数量非常多(成千上万),且每个区都很小,是典型问题特征。freelists,freelist_groups: 确认是否是 ASSM (NULL表示 ASSM)。
- 核心关注
- 查询表空间管理方式 (
DBA_TABLESPACES):SELECT tablespace_name, block_size, extent_management, allocation_type, segment_space_management FROM dba_tablespaces WHERE tablespace_name = (SELECT tablespace_name FROM dba_segments WHERE owner = '&owner' AND segment_name = '&segment_name');- 确认
extent_management=LOCAL(LMT)。 - 确认
segment_space_management=AUTO(ASSM)。这是主流。 - 关注
allocation_type:SYSTEM:AUTOALLOCATE(Oracle 自动管理区大小)。UNIFORM: 统一区大小。检查DBA_TABLESPACES的next_extent或USER_TABLESPACES的DEF_INITIAL_EXTENT看大小。
- 确认
- 查询表/索引存储参数 (
DBA_TABLES/DBA_INDEXES):SELECT table_name, pct_free, pct_used, ini_trans, maxtrans FROM dba_tables WHERE owner = '&owner' AND table_name = '&table_name'; SELECT index_name, pct_free, ini_trans, maxtrans FROM dba_indexes WHERE owner = '&owner' AND table_name = '&table_name'; -- 关联索引也可能有热点- 核心关注
pct_free: 对于插入为主的表,高pct_free(如 > 20%) 会导致块更快“填满”,需要更频繁分配新块,加剧位图块访问和TW争用。 ini_trans,maxtrans: 事务槽设置,影响块级并发,与TW关联不大,但极端设置可能导致其他等待(enq: TX - allocate ITL entry)。
- 核心关注
步骤 4: 分析空间操作频率和递归
- AWR 段统计 (
DBA_HIST_SEG_STAT):SELECT dhss.snap_id, TO_CHAR(s.begin_interval_time, 'YYYY-MM-DD HH24:MI') AS begin_time, dhss.owner, dhss.object_name, dhss.subobject_name, dhss.space_allocated_delta, -- 分配的空间变化 (字节) dhss.space_used_delta, -- 使用的空间变化 (字节) dhss.db_block_changes_delta -- 块修改次数 (间接反映 DML 强度) FROM dba_hist_seg_stat dhss JOIN dba_hist_seg_stat_obj dhso ON (dhss.obj# = dhso.obj# AND dhss.dataobj# = dhso.dataobj#) JOIN dba_hist_snapshot s ON (dhss.snap_id = s.snap_id AND dhss.instance_number = s.instance_number) WHERE dhso.owner = '&owner' AND dhso.object_name = '&segment_name' AND s.begin_interval_time BETWEEN ... AND ... -- 问题时段 ORDER BY s.snap_id;- 观察
space_allocated_delta和space_used_delta。在TW争用期间,如果space_allocated_delta很高,说明该段正在快速扩展(频繁分配新区),这是TW争用的直接证据。db_block_changes_delta高说明 DML 活跃。
- 观察
- 检查撤销空间:
- 查看 AWR 报告的 “Undo Statistics” 部分。关注
Undo segment count,Undo retention,Max Query Length,Transactions per Rollback,Out of Space Errors。 - 检查撤销表空间是否自动扩展?文件大小是否足够?是否有
ORA-01555或空间不足错误?高撤销空间压力会加剧递归TW争用。 - 查询
V$UNDOSTAT查看历史撤销空间使用情况。
- 查看 AWR 报告的 “Undo Statistics” 部分。关注
步骤 5: 综合分析与解决方案
根据排查结果,针对热点对象和根本原因采取措施:
- 增大区大小 (最有效): 这是减少
TW争用最直接、最有效的方法。UNIFORM表空间: 直接增大UNIFORM SIZE(例如从 1M 增大到 16M, 32M 甚至 64M 或更大)。ALTER TABLESPACE ... MINIMUM EXTENT ...可能需先设置,然后重建对象。AUTOALLOCATE表空间: 虽然不能直接设置,但可以重建对象并指定更大的INITIAL和NEXT区:-- 重建表 (需要停机或在线重定义) ALTER TABLE ... MOVE TABLESPACE ... STORAGE (INITIAL 64M NEXT 64M); -- 重建索引 ALTER INDEX ... REBUILD TABLESPACE ... STORAGE (INITIAL 64M NEXT 64M);- 足够大的
INITIAL/NEXT(如 64M, 128M)可以显著减少扩展频率。 - 评估段总大小,确保初始区能容纳合理数据量。
- 足够大的
- 降低
PCTFREE: 对于插入 (INSERT) 为主、后续更新 (UPDATE) 很少的表,适当降低PCTFREE(例如从 20% 降到 10% 或 5%)。这允许每个块容纳更多行,延缓新块分配需求。ALTER TABLE ... PCTFREE 10;- 重要: 修改
PCTFREE只影响新插入的数据。已存在的块不受影响。考虑重建表或让新数据自然填充。 - 警告: 如果表后续有较多导致行增长的
UPDATE,过低的PCTFREE会增加行迁移/行链接风险。
- 重要: 修改
- 使用分区 (Partitioning): 将大表、热表按逻辑范围(如时间)分区。
- 将插入操作分散到不同的分区(不同分区有不同的段头和位图块)。
- 显著减少对单个位图块集的争用。
- 需要应用设计配合(如按分区键插入)。
- 优化提交频率 (Batch Commit):
- 在应用程序中,确保不是每插入一行就提交一次。使用批量提交(例如每 1000 行或一定时间间隔提交一次)。
- 减少事务提交次数,也间接减少了空间管理元数据更新的频率(有时空间操作在提交时或提交附近发生)。
- 避免热点插入:
- 序列缓存 (
SEQUENCE CACHE): 如果主键是序列生成的,确保序列设置了足够大的CACHE(如CACHE 1000或更大)。避免多个会话频繁争用序列的enq: SQ - contention和序列值所在块,该块通常也是插入热点块。 - 反转键索引 (Reverse Key Index): 对于纯插入的索引,如果主键/唯一索引是单调递增的(如序列),考虑使用反转键索引打散索引叶块热点。但会牺牲范围扫描性能。
- 序列缓存 (
- 优化 ASSM (较少直接调整):
- ASSM 内部机制已优化。主要依靠增大区大小和分区来缓解位图块争用。
- 确保使用最新 Oracle 版本(新版本持续改进 ASSM)。
- 检查并优化撤销表空间:
- 确保撤销表空间足够大,使用
AUTOEXTEND或预分配足够空间。 - 设置合理的
UNDO_RETENTION(避免过长导致空间压力)。 - 监控撤销空间使用,避免
ORA-01555和空间不足导致的递归操作。
- 确保撤销表空间足够大,使用
- 参数调整 (谨慎):
_use_realfree_heap: 确认该隐含参数为TRUE(11g+ 默认)。除非有明确理由且经过严格测试,否则不要设置为FALSE。查询:SELECT x.ksppinm name, y.ksppstvl value FROM x$ksppi x, x$ksppcv y WHERE x.indx = y.indx AND x.ksppinm = '_use_realfree_heap';db_file_multiblock_write_count: 主要影响DBWn写脏块效率,对TW争用本身帮助有限,但优化整体 I/O 有益。保持默认或根据存储调整。
- 升级硬件/存储: 如果 I/O 子系统(特别是存放位图块的磁盘)是瓶颈(伴随高
db file sequential read/db file single write等待),升级到更快的存储(SSD/NVMe)能改善访问位图块的速度,从而稍微缓解TW获取后的操作时间,但不能减少TW争用发生的频率。解决争用频率还是靠前面几点。
关键诊断视图总结
- 整体/历史:
V$SYSTEM_EVENT,DBA_HIST_SYSTEM_EVENT, AWR/ASH 报告 (核心是定位对象和 SQL) - 会话级实时/历史:
V$SESSION_WAIT,V$SESSION,V$ACTIVE_SESSION_HISTORY,DBA_HIST_ACTIVE_SESS_HISTORY(核心是CURRENT_OBJ#,SQL_ID,P1,P2,P3) - 对象信息:
DBA_OBJECTS,DBA_SEGMENTS(核心INITIAL_EXTENT,NEXT_EXTENT) - 表空间信息:
DBA_TABLESPACES(核心EXTENT_MANAGEMENT,ALLOCATION_TYPE,SEGMENT_SPACE_MANAGEMENT) - 表/索引信息:
DBA_TABLES,DBA_INDEXES(核心PCT_FREE) - 段统计历史:
DBA_HIST_SEG_STAT(核心SPACE_ALLOCATED_DELTA,SPACE_USED_DELTA) - 撤销信息:
V$UNDOSTAT, AWR “Undo Statistics” - 参数:
V$PARAMETER,V$SYSTEM_PARAMETER,X$KSPPI,X$KSPPCV(查_use_realfree_heap)
重要提示
TW争用是空间管理并发瓶颈: 它本质反映了高并发 DML(尤其是插入)下,对空间管理元数据(位图块)的串行化修改需求成为了性能瓶颈。- 增大区大小是治本之策: 增大
INITIAL/NEXT或UNIFORM SIZE能最直接、最显著地减少空间分配操作次数,从而减少TW争用事件的发生频率。这是最推荐的首要解决方案。 - ASSM 优于 MSSM: 坚持使用 ASSM (
SEGMENT SPACE MANAGEMENT AUTO),不要退回到手动管理。 - 分区是水平扩展利器: 对于无法简单增大区或降低
PCTFREE的超高并发插入场景,分区是将负载分散到多个独立段(及其位图块)的关键手段。 - 批量提交和序列缓存是应用优化点: 应用程序设计对预防
TW争用至关重要。 - 监控递归操作: 不要忽视撤销空间问题或其他递归空间操作对
TW争用的贡献。 - 测试: 任何存储参数修改(特别是
PCTFREE降低)或表重建,都应在测试环境充分验证。
通过以上系统的排查和优化,你可以有效地诊断和解决 enq: TW - contention 等待事件,提升高并发 DML 场景下的数据库性能。
欢迎关注我的公众号《IT小Chen》

被折叠的 条评论
为什么被折叠?



