MySQL UPDATE大表时看似锁全表,实为行锁升级+MVCC版本链拉长导致阻塞;分批更新须基于主键范围切分、控单事务≤1000行、加短延时,禁用OFFSET;无索引时优先加索引或改用主键子查询。UPDATE 大表时为什么锁全表MySQL 的 UPDATE 在未命中索引或扫描行数过多时,InnoDB 会升级锁粒度------从行锁退化为间隙锁甚至表级意向锁,配合事务隔离级别(尤其是 REPEATABLE READ),实际效果就是"像锁了整张表"。你看到的"卡住其他查询",往往不是真锁表,而是大量行锁堆积 + MVCC 版本链拉长,导致后续语句等锁、等回滚、等 purge 线程清理旧版本。常见错误现象:SHOW PROCESSLIST 里一堆 Updating 状态;SELECT 查询明显变慢甚至超时;INFORMATION_SCHEMA.INNODB_TRX 显示事务长时间运行且 TRX_ROWS_LOCKED 高达百万级。分批 UPDATE 的核心控制点分批不是简单加个 LIMIT 就完事。关键在三件事:用主键/唯一索引驱动分页、控制每批事务大小、避免 OFFSET 滚动扫描。必须基于主键范围切分,例如:WHERE id BETWEEN ? AND ?,而不是 LIMIT 1000 OFFSET 10000(后者越往后越慢,且可能漏数据)每批提交前确认影响行数,用 ROW_COUNT() 判断是否还有数据可处理单事务控制在 1000 行以内(具体看单行大小和 binlog 格式,STATEMENT 模式下大事务更危险)批次间加短延时(如 SLEEP(0.1)),缓解主从复制压力和锁竞争示例逻辑(伪代码):SET @start_id = 0;WHILE @start_id < (SELECT MAX(id) FROM t) DO UPDATE t SET status = 1 WHERE id > @start_id AND id <= @start_id + 1000; SELECT ROW_COUNT() INTO @affected; IF @affected = 0 THEN LEAVE; END IF; SET @start_id = @start_id + 1000; COMMIT; DO SLEEP(0.1);END WHILE;WHERE 条件没走索引怎么办这是最常踩的坑:以为加了 LIMIT 就安全,结果执行计划显示 type: ALL,全表扫描+全表加锁。分批的前提是每次都能快速定位到下一批起点。 文心快码 文心快码(Comate)是百度推出的一款AI辅助编程工具
相关推荐
笃行3501 小时前
数据库性能优化的五处内核改造,KingbaseES 配了四件诊断工具非优秀程序员3 小时前
第02章 杭电的英语老师与一台服务器|《互联网产品恩仇录》用户956256254298 小时前
跟做:Firecrawl 单页转 Markdown 再丢进沙箱总结SelectDB8 小时前
SelectDB 是哪个公司的?是国产数据库吗?一篇讲清飞轮科技与 Apache Doris 的关系威哥爱编程8 小时前
模拟面试智能体开发实战 02:回答等半分钟,谁还愿意练?把服务端和流式输出搭起来这个DBA有点耶8 小时前
库内计算推理:一条SQL背后的算子融合,和外挂方案差了几次网络往返威哥爱编程8 小时前
模拟面试智能体开发实战 01:面试挂了都不知道挂在哪?用 Python 给自己造一个随叫随到的 AI 面试官2601_967980119 小时前
Python行情API量化 02:顺序拉 20 要 2 秒?并发批量把时间压到 0.5 秒伞伞悦读9 小时前
【第81期】特征缩放怎么选:标准化、MinMax 与 Robust 的原理、泄漏对照和完整实验新*9 小时前
从一段 WebSocket 代码聊开:bytes 不是 zlib、binaryType 决定一切,15MB 大消息的零拷贝优化