首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

行锁争用问题的分析方法

今天遇到两起“锁表”问题的技术支持,都是“药品库存”相关的,业务层面表现为发药操作卡死,或要等很久才完成,严重影响窗口业务的使用。

数据库层面表现为,等待事件'enq: TX - row lock contention'。

这类问题,如果只是从发生等待事件的会话当时执行的SQL去分析,很难查到问题原因,可能完全想不通为什么这么简单的一条SQL会卡死。

之前写过一篇文章,介绍了两种常见的“锁表”问题,下面分析今天遇到的两个案例中的一个,再次对行锁争用的问题进一步的说明,分享解决这类问题的方法。

当发生“锁表”问题后,可以通过查AWR或ASH来分析问题,一般来说,查ASH更方便一些,因为可以获取一个较短时间内(常用15分钟)的信息,快速定位问题。

如下图所示:

从中我们看到,在更新“病人余额”和“药品库存”时发生了行锁争用。

进一步,可以看到是如下两个存储过程的调用:

如果仅仅看这几条Update操作相关的SQL,该SQL很简单,难以理解为什么这么一条SQL会被阻塞。

遇到这类问题时,我们需要从原理来理解,从业务层面去分析。

1.更新一行数据后,如果不提交事务会发生什么问题?

其他并发会话,要更新相同的一行数据,就只有等待这个事务提交后才能执行完成。

2.有哪些情况会引起事务没有立即提交?

常见的有,更新一行数据后,存储过程中查询或处理别的数据,如果耗时过长,例如:大表全表扫描,耗时一分钟。那么之前在同一个过程中更新的那一行数据,在此期间就是一直锁住的。

还有比较常见的情况就是,调用存储过程的界面程序,没有及时提交事务,在事务中进行一些耗时的操作,例如:弹出提示等待操作人员处理,调用远程接口(常见的,例如:医保接接),执行打印操作等。

简单的说,茅坑有限,如果有人占倒茅坑不拉屎,其他人就只有等待。

所以,如果只是看“Update药品库存”这一条语句,很难理解到这个案例中,为什么“Select* From病人费用查询”这条语句的全表扫描会是导致这个问题的根本原因。

当出现这类问题时,首先从ASH或AWR中查,如果有耗时的SQL,特别是全表扫描的,先解决了再说,不要觉得跟当前行锁的语句完全无关就忽略了。

如果没有这类SQL,那就要想想应用程序方面的原因了,特别是一些第三方程序,或相关接口程序,往往会缺乏性能方面的考虑。

这个案例中的问题解决,最终定位到下面这条SQL:

这是一个第三方应用程序“zl_卫材自动打印.exe”中调用的SQL。

SQL中的问题就是对视图进行外连接,导致没有使用到预期的索引。

解决办法是,改写SQL中的视图“病人费用记录”,这是一个由“门诊费用记录”和“住院费用记录”进行Union查询而来的,改为直接用“基表”来与其他表时行连接,或者简单的加一个rule提示字来固定执行计划。

这条语句快了,更新“药品库存”的事务就会很快完成,就能够避免行锁争用。

当然,可能还有其他的原因,以上只是列举最常见的原因。

产生等待事件'enq: TX - row lock contention',其他原因还包括:

1.并发会话,插入相同主键值的记录;

2.位图索引的并发更新。

3.Oracle的BUG等。

更多信息,可查看Oracle官网的一篇文章:

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180209G1EZID00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券