rac 会放大 enq: tx - row lock contention,因其依赖 ges 跨实例协调锁,增加网络开销与等待时间,暴露应用层行级串行化瓶颈;常见根源为 sequence 未缓存、索引热块及事务未及时提交。

Oracle RAC 下 enq: TX - row lock contention 频发,不是 RAC 本身设计缺陷,而是单点锁竞争在多实例环境里被放大——本质仍是应用或 SQL 层面的行级串行化瓶颈,只是 RAC 让冲突更可见、影响更广。
为什么 RAC 会让 enq: TX 更容易暴露
RAC 中多个实例共享同一份数据,但锁管理仍需通过 Global Enqueue Services(GES)协调。当两个会话分别连到不同节点、同时 UPDATE 同一行时,锁请求必须跨实例通信,比单实例多了网络往返和全局队列仲裁开销。这导致:
-
enq: TX等待时间变长,原本毫秒级的锁等待在 RAC 中可能变成几十甚至上百毫秒 - AWR 报告中该事件更容易“上榜”,尤其在 Top 10 Foreground Events 里持续占高比例
- 监控看到的不是“锁没拿到”,而是“锁在等另一个实例确认”,掩盖了真正源头是应用逻辑
最常踩的三个坑:sequence、索引热块、事务粒度
排查时优先盯这三处,80% 的 RAC 行锁激增都源于此:
-
SEQUENCE未启用CACHE或误开了ORDER:每次取 ID 都要争抢序列号内存结构,引发enq: SQ - contention连带触发 TX 锁排队。查法:SELECT sequence_name, cache_size, order_flag FROM dba_sequences;建议设为CACHE 1000 NOORDER - 单调递增字段做索引前导列(如
id或created_date):所有新插入都挤在索引最右叶块,造成gc buffer busy acquire和enq: TX双重等待。改用REVERSE KEY索引,或加哈希扰动(如按MOD(id, 16)分区) - 应用层事务过长或未提交:一个会话 UPDATE 后不 COMMIT,其他实例的 UPDATE 就卡在 TX 队列里。不是数据库慢,是应用卡在业务逻辑或异常未处理
怎么快速定位是哪行、哪个会话在锁
别只看 AWR,直接查实时视图更准:
- 找阻塞源头:
SELECT blocking_session, blocking_session_serial#, sql_id FROM v$session WHERE blocking_session IS NOT NULL - 查锁住的具体行:
SELECT do.object_name, row_wait_obj#, row_wait_file#, row_wait_block#, row_wait_row# FROM v$session s JOIN dba_objects do ON s.row_wait_obj# = do.object_id WHERE s.row_wait_obj# > 0 - 结合
v$locked_object和v$transaction看事务持续时间,超 5 秒未提交的基本可判定为应用问题
真正难处理的,从来不是“怎么查锁”,而是“为什么这一行总被反复更新”——比如订单状态表里某个订单被并发调用多次状态变更,或者计数器字段没有用 SELECT FOR UPDATE SKIP LOCKED 控制竞争。这些细节不会出现在 AWR 里,得翻应用日志和 SQL 调用链。











