[已解决] MySQL 大表频繁修改索引列会造成锁等待吗?

破案

最后发现报表中有个更新销量的脚本,update中有个包含order_items的子查询导致锁表,一直没发现是因为关注的点都是splunk中出问题的时间段,如果把时间拉长到一个月,就能看到三四个密集的慢查询,都是锁释放导致的。把这个sql优化掉就解决了。

问题描述

场景是公司有一张大约500万行数据,140列的订单商品表(order_items),涉及的列有 id 自增主键, state_id 有索引idx_state_id 状态ID。

在用户操作自己的订单和后台工厂数据回调时会进行商品状态更新。

伪代码如下,根据主键条件查询数据,并更新另一个索引列,状态列索引区分度低。

foreach ($ordersItems as $orderItem) {
    // update order_items set state_id = ? where id = ?
}

实际运行时有时会出现 wait lock timeout exceeded 的报错,等待锁释放超过50s后自动失败。

猜测原因

死锁

leader 让我去排查原因,给出的方向是死锁/锁表或其他原因。我尝试了一些可能的原因,也详细查了资料,排除了一些可能的原因,但是还没有找到真正的问题原因。

首先排除是死锁导致的

理由一:死锁异常是检测到死锁deadlock try restarting transaction,日志中没有这样的记录。

理由二:死锁是两个事务排他锁冲突导致的,这里没有开启事务(至少是没有找到事务),所以我认为不是死锁导致的。

锁表

分析MySQL slow SQL log,除了在某一时段出现多次超过50s的SQL,这段时间内和前后都有5s - 40s左右的记录,他们之间也有不超过50s的间隔的记录。如果锁表日志应该更密集,也不应该只出现在某几个时段。

其他原因

一种可能是其他事务加锁没有释放,但按道理这样的查询会被记录到慢sql,除非在事务加锁后进行了如读取aws s3数据或其他耗时的操作。这样理论是可能的,但很难排查。

另一种可能是由于频繁操作索引列,会不会由于某些性能原因导致自己锁自己?比如更新 idx_state_id 时由于瞬间操作过于频繁或数据原因更新缓慢?

提问主要是希望大家能对其他原因的第二点进行讨论,模拟环境虽然比较困难,但我也在尝试,如果理论能证实/证伪就能节省很多时间,先感谢大家了。

为码农摸鱼事业而奋斗
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 2

个人觉得还是因为前面有一直在运行的事务吧 不是可以运行
select * from information_schema.innodb_trx

查看死锁的吗 个人观点。

4年前 评论
Kamicloud (楼主) 4年前
Remember (作者) 4年前
Kamicloud (楼主) 4年前

大表还要频繁修改索引列?这是什么操作?

4年前 评论
Kamicloud (楼主) 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!