← 返回题目列表

MySQL 热点行更新为什么会成为瓶颈?如何优化库存和计数器场景?

困难 第 25 / 28 题 更新于 2026/08/06
MySQL热点行行锁库存扣减

简化版

热点行是大量并发请求更新同一行,例如秒杀库存、文章点赞数、账户余额。InnoDB 行锁会让同一行更新串行化,导致锁等待、吞吐下降和延迟抖动。优化思路包括减少同步更新频率、拆分热点、库存分桶、异步汇总、乐观扣减、队列串行化、缓存前置和限流。关键是不要让所有流量都打到数据库同一行。

详细版

数据库擅长保证一致性,但同一行的写冲突无法无限并发。比如 UPDATE stock SET quantity = quantity - 1 WHERE sku_id = 1 AND quantity > 0,语义正确,但所有人都抢同一个 sku_id 时,行锁会排队。

优化要先判断业务一致性要求。余额和支付强一致,不能随便异步;点赞数、浏览量可以延迟汇总;库存可以分桶或预扣。不同场景的优化方式不同。

面试中要把“热点行是锁竞争问题”讲清楚,而不是只说加索引。

完整版教学

一、热点行是什么

热点行是被大量并发访问的同一行。

读热点可以靠缓存缓解。

写热点更麻烦,因为更新需要互斥。

InnoDB 对同一行更新会加行锁。

并发越高,等待队列越长。

二、典型 SQL

UPDATE sku_stock
SET quantity = quantity - 1
WHERE sku_id = 1001
  AND quantity > 0;

这条 SQL 可以保证不超卖。

但高并发下所有请求都更新同一行。

最终吞吐受单行更新能力限制。

三、常见场景

场景一致性要求优化方向
秒杀库存分桶、预扣、队列、限流
点赞数中低缓存计数、异步落库
浏览量批量汇总
账户余额极高严格事务、减少并发入口
排行榜计数Redis 聚合后周期落库

四、库存分桶

把一个商品库存拆成多个库存桶。

请求按随机或哈希选择桶扣减。

多个桶分散写入压力。

最终库存是多个桶之和。

缺点是实现复杂度和回收逻辑增加。

五、异步汇总

点赞、浏览、曝光这类指标不一定要实时强一致。

可以先写缓存或消息队列。

再按批次汇总到 MySQL。

这样减少单行高频更新。

但要处理丢消息、重复消费和最终一致性。

热点行优化的本质是把“单点串行写”改成“分散写、批量写或限流写”。

六、数据库侧注意点

索引要保证 UPDATE 精确定位行。

事务要尽量短。

避免在持锁期间调用外部服务。

观察锁等待和死锁日志。

热点写入要结合业务限流,不能只靠数据库硬扛。

七、误区和追问

  • 误区:热点行加索引就能解决。 索引只能更快定位行,不能消除同一行更新互斥。
  • 误区:库存扣减可以随便异步。 库存涉及超卖风险,要看业务能否接受预扣和补偿。
  • 误区:Redis 计数就完全不用落库。 仍要考虑持久化、对账和恢复。
  • 追问:余额场景能分桶吗? 通常不适合随意分桶,余额强一致要求更高。
  • 追问:库存分桶有什么问题? 桶间不均、剩余库存回收、查询总量和补偿逻辑更复杂。
  • 追问:如何发现热点行? 看锁等待、慢 SQL、同一主键更新频率和业务访问分布。

八、面试收束

回答时先指出它是行锁竞争。

再按业务一致性选择分桶、异步、队列或限流。

最后强调强一致场景不能为了性能破坏正确性。

九、常见误区与追问

  • 误区:只记住 MySQL 热点行更新为什么会成为瓶颈?如何优化库存和计数器场景? 的结论就够了。 数据库题通常还要解释索引、事务、锁、执行计划或一致性边界,否则很容易被追问打穿。
  • 误区:能查出结果就说明 SQL 或设计没问题。 还要看数据量扩大到 100 万行后是否仍能走合适索引、是否产生临时表或锁等待。
  • 误区:所有场景都追求强一致。 读写分离、缓存、异步任务都可能牺牲一部分实时性,关键是说明业务是否允许。
  • 追问:线上变慢时你先看什么? 先看慢 SQL、执行计划、扫描行数、锁等待和连接池,再判断是 SQL 写法、索引还是并发问题。
  • 追问:如何证明这个方案可落地? 给出一个小数据例子,再补充约束、失败场景和回滚方案,避免只停留在概念层。

十、加强记忆

记 MySQL 热点行更新为什么会成为瓶颈?如何优化库存和计数器场景? 时,把它压成“语义正确、执行高效、并发安全”三件事。先说清这个知识点解决什么数据库问题,再用 1 个带数字的小例子说明数据量一大为什么会出差异,最后补上索引、锁、事务或执行计划里的易错点。这样面试官无论追问 SQL 写法、线上慢查,还是并发一致性,你都能沿着同一条线继续展开。