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辅助编程工具
相关推荐
默_笙14 小时前
🍙 给每个请求过安检:FastAPI 是怎么把校验写进类型注解的qq_4260039615 小时前
启动playwright录制codegen生成自动化测试脚本虎头金猫15 小时前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺长沙三为智能科技15 小时前
家政小程序开发从0到上线:五阶段交付流程与验收清单此时不提桶,更待何时15 小时前
01-06-A-JVM排查实战详解伞伞悦读15 小时前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__这个DBA有点耶16 小时前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核DBA_G16 小时前
从地面到云霄:GBase数据库在民航三大场景的落地实践自由能燃气设备16 小时前
商用全预混低氮冷凝锅炉免费方案vs付费方案对比+选型避坑指南只睡四小时16 小时前
Canvas 弹道联机实战:700 行 + 固定时间步长