一次因缺失索引引发的线上锁超时事故

前言

周四深夜,万籁俱寂,刚要入睡,手机突然响起。

"线上列表查询接口返回空数据,群里已经炸锅了------大量用户反馈 APP 无法正常使用,赶紧排查!"

听到这句话,我瞬间清醒,睡意全无,立刻从床上弹起。

问题定位

匆忙打开电脑,连上生产环境,首先检查 MySQL 的运行状态。观察到 CPU 和内存使用率都很低,基本可以排除数据库因负载过高导致响应异常的可能。

接着查看应用的错误日志,发现大量如下异常:

java 复制代码
Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: 
Lock wait timeout exceeded; try restarting transaction

nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: 
Lock wait timeout exceeded; try restarting transaction

显然,问题出在锁等待超时上。于是,我立即执行以下 SQL 查询,定位造成阻塞的具体事务:

sql 复制代码
SELECT  
    dl.REQUESTING_ENGINE_TRANSACTION_ID AS waiting_trx_id,  
    dl.BLOCKING_ENGINE_TRANSACTION_ID AS blocking_trx_id,  
    l2.OBJECT_NAME AS table_name,  
    l1.LOCK_DATA AS blocked_by_data,  
    t1.trx_query AS waiting_sql,  
    t2.trx_query AS blocking_sql,  
    t2.trx_started AS blocking_started  
FROM performance_schema.data_lock_waits dl  
JOIN performance_schema.data_locks l2  
  ON dl.REQUESTING_ENGINE_LOCK_ID = l2.ENGINE_LOCK_ID  
JOIN performance_schema.data_locks l1  
  ON dl.BLOCKING_ENGINE_LOCK_ID = l1.ENGINE_LOCK_ID  
LEFT JOIN information_schema.innodb_trx t1  
  ON dl.REQUESTING_ENGINE_TRANSACTION_ID = t1.trx_id  
LEFT JOIN information_schema.innodb_trx t2  
  ON dl.BLOCKING_ENGINE_TRANSACTION_ID = t2.trx_id;

查询结果清晰地显示出一条正在等待锁的 SQL(见下图):

顺着这条 SQL,我迅速定位到对应的业务代码。问题根源浮出水面:一个未加索引条件的长事务执行了 UPDATE 操作

根本原因分析

该表数据量超过 90 万行,且除主键外没有任何二级索引。在 InnoDB 存储引擎下,执行如下语句:

sql 复制代码
UPDATE table SET col = val WHERE non_indexed_col = xxx;

由于 WHERE 条件字段无索引,MySQL 不得不进行全表扫描 。在可重复读(RR)隔离级别下,InnoDB 会对扫描到的每一行加记录锁 ,甚至可能加上间隙锁(Gap Lock) 。结果就是------整张表几乎被锁住,其他并发事务在尝试获取锁时纷纷超时,最终导致接口无数据返回、APP 功能大面积不可用。

解决方案与最佳实践

为避免类似问题再次发生,我们总结了以下几点优化建议:

  • 避免长事务:将大范围更新拆分为小批量操作(如分页更新),缩短事务持有时间。
  • 确保 WHERE 条件字段有索引:防止全表扫描引发的行锁膨胀。
  • 及时提交事务:减少锁资源的占用时长,提升系统并发能力。

这次深夜"救火"经历再次提醒我们:在高并发场景下,一个看似微小的索引缺失,可能就是压垮系统的最后一根稻草

相关推荐
我是一颗柠檬36 分钟前
【MySQL全面教学】MySQL性能优化实战Day13(2026年)
数据库·后端·sql·mysql·性能优化·database
小江的记录本1 小时前
【JVM虚拟机】JVM调优:常用JVM参数、调优核心指标、OOM排查、GC日志分析、Arthas工具使用(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·后端·python·spring·面试
程序员cxuan1 小时前
我花了两天时间,终于把 Codex 额度掉太快的问题整明白了!!
人工智能·后端·程序员
IT_陈寒1 小时前
Vue这个动态响应坑把我整不会了
前端·人工智能·后端
金銀銅鐵1 小时前
[Java] 用图形化界面演示 iadd, isub, iconst_<i> 指令的效果
java·后端·python
AskHarries1 小时前
做国内还是出海
后端
日月云棠2 小时前
10 Integer —— 最常用的整数包装类深度解析
java·后端
大鸡腿同学2 小时前
大模型为何总 “胡说八道”?做完 RAG 知识库,我看懂了它的底层逻辑
后端
一 乐2 小时前
高校实习信息发布网站|基于Spring Boot的高校实习信息发布网站的设计与实现(源码+数据库+文档)
java·数据库·spring boot·后端·论文·毕设·高校实习信息发布网站
安久12 小时前
springboot图片上传至服务器本地保存
后端