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辅助编程工具
相关推荐
ZhengEnCi42 分钟前
P2L-Matplotlib饼图完全指南-从数据可视化到图表定制的Python绘图利器曲幽44 分钟前
你的REST接口还在“过度投喂”数据吗?——FastAPI + GraphQL实战避坑指南用户8358086187912 小时前
基于 Self-RAG 与列表级重排序的进阶 RAG 系统设计与实现xiezhr3 小时前
逛GitHub发现了一款免费的带AI功能的数据库管理工具Warson_L18 小时前
Python `Annotated` 与 LangGraph Reducer 学习笔记韩师傅18 小时前
海天线算法的前世今生韩师傅19 小时前
当你的甲方设备过烂,要如何快速出效果?Warson_L19 小时前
LangGraph的MessageState and HumanMessage韩师傅19 小时前
当你的甲方吐槽天空不够蓝,你应该如何应对Warson_L20 小时前
python的类&继承