← 返回题目列表

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

困难 第 25 / 28 题 更新于 2026/07/30
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、同一主键更新频率和业务访问分布。

八、面试收束

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

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

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