前言

最近看 awr 报告时,经常会看到一些 enq: TX - row lock contention 的等待事件,所以简单研究一下如何排查,仅为个人所见,如有异议或者修正还请评论指出,谢谢!

通常,产生enq: TX - row lock contention事件的原因有以下几种可能:

  • 不同的session更新或删除同一条记录;
  • 唯一索引有重复索引;
  • 位图索引同时被更新或同时并发的向位图索引字段上插入相同字段值;
  • 并发的对同一个数据块上的数据进行update操作;
  • 等待索引块完成分裂;

现象

应用反馈系统使用存在延时,需要排查情况。查看监控服务器,发现数据库存在 enq: TX - row lock contention 锁的情况。

排查

首先确认发生问题的时间段,然后抓取问题时间段的报告来分析。

AWR 报告

执行 sqlplus / as sysdba @?/rdbms/admin/awrrpt.sql 输入对应时间段的信息,获取 awr 报告。

Top 10 Foreground Events by Total Wait Time

也可通过 awrcrt sqlplus / as sysdba @awrcrt.sql 来获取多段性能指标信息:

Segments by Row Lock Waits

通过观察 awr 报告中段的统计信息章节 Segments by Row Lock Waits 项,可以发现发生锁的对象主要是两张表 ABA 表的索引:

与应用确认后,发现其中一张表 A 为核心业务表,暂时怀疑另一张表可能存在问题,这里称之为表 B,所以 A 表暂且不考虑。

SQL ordered by Elapsed Time

通过 搜索关键字,查出 B 表对应的 UPDATE 语句,执行较为频繁,先记录待查看:

sql_id 为:2xb71ufa5wmrh

ASH 报告

抓取对应时间段的 ash 报告,查看是否存在有用信息。

执行 sqlplus / as sysdba @?/rdbms/admin/ashrpt.sql 获取报告:

Top User Events

Top SQL with Top Events

Top Blocking Sessions

Top DB Objects

从以上信息,不难看出,与 awr 报告分析出的结果吻合,同样的 sql_id 和 对象,并且获取到了 blocking sid

ADDMRPT 报告

有时,也可以通过抓取 addmrpt 报告来辅助看一下问题,可能有奇效。

执行 sqlplus / as sysdba @?/rdbms/admin/addmrpt.sql 获取 addmrpt 报告:

Summary of Findings

Finding 2: Row Lock Waits

同样都指向了 B 表和 sql_id 为 2xb71ufa5wmrh 的这条语句。

应用确认

经过应用确认,该条 sql 是一张核心业务表的一个触发器发起的,业务表每次新增提交时,会去执行该 sql 更新数据。由于未确认该触发器具体作用,因此无法尝试禁用来观察。

写在最后

经过排查,大部分的阻塞都是因为 sql_id 为 2xb71ufa5wmrh 的语句导致,具体也可以通过以以下 sql语句 来进行查询:

select DISTINCT b.sql_id,c.blocked_sql_id
  from DBA_HIST_ACTIVE_SESS_HISTORY b,
       (select a.sql_id as blocked_sql_id,
       a.blocking_session,
               a.blocking_session_serial#,
               count(a.blocking_session)
          from DBA_HIST_ACTIVE_SESS_HISTORY a
         where event like '%enq: TX - row lock contention%'
           and snap_id between 18835 and 18836
         group by a.blocking_session, a.blocking_session_serial#,a.sql_id
        having count(a.blocking_session) > 100
         order by 3 desc) c
 where b.session_id = c.blocking_session
   and b.session_serial# = c.blocking_session_serial#
   and b.snap_id between 18835 and 18836;

需自行替换对应的快照范围 snap_id 值,查询结果 sql_id 为被阻塞,blocked_sql_id 为阻塞 ID。

如有问题,请及时指正,谢谢

文章来源:https://www.modb.pro/db/101821

最后修改:2021 年 11 月 14 日
如果觉得我的文章对你有用,请随意赞赏