确认UPDATE卡住是否因锁:先查information_schema.INNODB_TRX找长时间RUNNING事务,再查INNODB_LOCK_WAITS看阻塞链;结合TRX_ROWS_MODIFIED判断是否可安全KILL;避免全表扫描锁升级,确保WHERE条件走索引。

UPDATE 卡住时怎么快速确认是不是被锁了
直接查 information_schema.INNODB_TRX 和 information_schema.INNODB_LOCK_WAITS,这是最准的起点。别先猜索引或网络问题,90% 的“无响应”更新卡在事务锁上。
-
SELECT * FROM information_schema.INNODB_TRX ORDER BY TRX_STARTED;看谁的事务启动最早、运行最久,重点关注TRX_STATE = 'RUNNING'但长时间没提交的 - 搭配
SELECT * FROM information_schema.INNODB_LOCK_WAITS;,如果有记录,说明确实存在阻塞链:某事务在等另一个事务释放锁 - 注意
TRX_MYSQL_THREAD_ID,用它去SHOW PROCESSLIST找到对应连接,看它在执行什么 SQL、是否处于Sleep状态却还拿着事务
WHERE 条件没走索引导致全表扫描+锁升级
UPDATE 语句若 WHERE 字段没索引,InnoDB 会扫全表,每行加记录锁(Record Lock),再升级成间隙锁(Gap Lock)或临键锁(Next-Key Lock),锁范围远超预期——这会让后续很多操作排队等锁。
- 用
EXPLAIN FORMAT=JSON UPDATE ...(MySQL 8.0+)或先改写为SELECT加EXPLAIN,确认key字段是否为NULL - 常见坑:对
TEXT/BLOB字段做前缀索引后,在 WHERE 中用了LIKE '%abc'或函数如UPPER(col),索引失效 - 复合索引要注意最左匹配:
INDEX(a,b,c)支持WHERE a=1 AND b>10,但不支持WHERE b=10单独出现
KILL 连接前必须看 TRX_ROWS_MODIFIED
盲目 KILL 正在写数据的事务,可能触发长回滚(rollback),反而让锁持有更久。真正要杀的是那些“啥也没改却占着茅坑”的连接。
- 查
INNODB_TRX里的TRX_ROWS_MODIFIED:值为 0 且TRX_STATE = 'LOCK WAIT',大概率是纯等待者;值很大且持续增长,说明它自己就是源头 - 别只看
PROCESSLIST的Time列——sleeping 连接可能刚提交完,也可能刚开启事务还没执行任何语句,得结合TRX_STARTED和TRX_ROWS_MODIFIED综合判断 - 如果确认要 KILL,优先用
KILL QUERY <code>thread_id(只中断当前语句),而不是KILL <code>thread_id(中断整个连接并触发回滚)
批量 UPDATE 分片执行避免锁表时间过长
一次更新几十万行?InnoDB 会把所有涉及的页都加锁,其他查询/更新全得排队。这不是性能问题,是锁资源争抢问题。
- 按主键分段:比如
WHERE id BETWEEN 10000 AND 19999,每次最多 5000 行,配合LIMIT和ORDER BY id防止漏行 - 每批之间加短延时(如 100ms),给其他事务腾出执行窗口,避免锁队列越堆越长
- 避免在高峰期跑大更新;如果业务允许,把
UPDATE拆成SELECT + 应用层处理 + 多条小 UPDATE,控制锁粒度更细
锁冲突不是配置调参能绕开的,本质是事务边界和访问模式的问题。最容易被忽略的,是应用层没显式 COMMIT 或异常路径遗漏了 ROLLBACK——一个没关的事务,能让整张表堵死半小时。


















