Oracle AWR案例分析: 诊断‘enq: TX - row lock contention‘等待事件
全网最全面的Oracle AWR 专栏,持续更新中…
在一个繁忙且健康的数据库环境中,多会话同时修改相同数据行是不可避免的。当这种情况发生时,一个会话必须等待另一个完成提交,这就引发了 “enq: TX - row lock contention” 等待事件。
在高并发的数据库中,适度的行锁竞争是正常现象,但若竞争过度,则会严重影响系统的可扩展性。本节将通过一个实际案例来说明如何诊断这种等待事件。
AWR 报告中的症状

从"Top 10 Foreground Events by Total Wait Time" 中,我们看到:
- “enq: TX - row lock contention” 事件发生了 20次.
- 这个世界平均等待时间超过了 4 秒。
- 它占总 DB Time的 21.6%。
接着,在 “Segment Statistics” 下的 “Segments by Row Lock Waits” 子部分中,我们可以找到引发竞争的对象。

从结果可以确认,所有 20 次竞争都发生在表 “WAREHOUSES” 上。

在 “SQL Statistics” 部分,我们发现了一条可疑的 SQL 语句。通常情况下,一条 SQL 的 %CPU 与 %IO 总和应接近 100%,但这条 SQL 的两者之和仅为 2.15%。这表明其大部分时间并未用于 CPU 或 I/O,而是等待其他事件。
一个合理的推断是,该 SQL 的时间主要消耗在 “enq: TX - row lock contention” 等待上,理由如下:
- 在 Top Event 列表中,除了CPU和IO外的一较长时间等待事件是 “enq: TX - row lock contention”。
- 该 SQL 的总执行时间为 90.74 秒,与该等待事件的 88.4 秒很接近。
- SQL 文本以 “UPDATE WAREHOUSES SET WAREHOUS…” 开头,与前文中锁竞争的对象 “WAREHOUSES” 相匹配。
当然,也可以使用$ORACLE_HOME/rdbms/admin/awrsqrpt.sql 生成针对该 SQL 的单独 AWR 报告以进一步分析,但此处我们跳过这一步。
使用ASH精确定位被锁数据行
到目前为止,我们已确定了触发 “enq: TX - row lock contention” 的 SQL 语句和对象。通常,解决行锁竞争的任务属于开发人员的职责,他们需要通过修改应用逻辑或 SQL 语句来避免竞争。但 DBA 可以进一步协助开发人员,帮助他们精确定位被锁定的具体行。这能快速判断是哪一业务逻辑部分导致了问题。
当 ASH 捕获到 “enq: TX - row lock contention” 等待时,它会记录以下四个字段:CURRENT_OBJ#、CURRENT_FILE#、CURRENT_BLOCK#、CURRENT_ROW#。通过这些字段,我们可以生成被锁记录的 rowid,从而定位具体的行。 以下 SQL 用于实现这一逻辑:
SELECT ob.owner, ob.object_name,dbms_rowid.rowid_create(rowid_type => 1,object_number => ob.data_object_id,relative_fno => sh.current_file#,block_number => sh.current_block#,row_number => sh.current_row#) AS row_id,COUNT(*) AS occurrence_countFROM dba_hist_active_sess_history shJOIN dba_objects ob ON sh.current_obj# = ob.object_idWHERE sh.snap_id = 2226AND sh.event = 'enq: TX - row lock contention'GROUP BY ob.owner, ob.object_name, dbms_rowid.rowid_create(rowid_type => 1,object_number => ob.data_object_id,relative_fno => sh.current_file#,block_number => sh.current_block#,row_number => sh.current_row#)ORDER BY occurrence_count DESC;
输出结果如下:
OWNER OBJECT_NAME ROW_ID OCCURRENCE_COUNT
YUAN WAREHOUSES AAAR2FAAFAAJibBABo 5
YUAN WAREHOUSES AAAR2FAAFAAJibBAC6 2
YUAN WAREHOUSES AAAR2FAAFAAJibBACM 2
YUAN WAREHOUSES AAAR2FAAFAAJibBABU 1
YUAN WAREHOUSES AAAR2FAAFAAJibBACU 1
YUAN WAREHOUSES AAAR2FAAFAAJibBAAV 16 rows selected.
从输出的结果可以看出,出现次数最多的记录是 5 次,它的ROWID是’AAAR2FAAFAAJibBABo’。 我们可以根据其 rowid 查看对应的行内容:
SQL> select * from yuan.warehouses where rowid='AAAR2FAAFAAJibBABo';
这样,我们就能精确定位到被锁的具体行。
这就是使用 AWR 与 ASH 相互配合,由宏观到微观的进行数据库故障诊断典型例子。
号主在certview.oracle.com网站上的证书清单截图。

关于号主,姚远:
- Oracle ACE(Oracle和MySQL数据库方向)
- 华为云最有价值专家
- 《MySQL 8.0运维与优化》的作者
- 拥有数十项数据库认证
- 曾任IBM公司数据库部门经理
- 20+年DBA经验,服务2万+客户
- 精通C和Java,发明两项计算机专利
- 两次获得国家部级奖
