凌晨跑批后接口开始超时,update 全表状态一直排队,innodb_trx 里有一条 trx_started 是 40 分钟前,trx_rows_locked 显示 26 万。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,一个事务开了没提交,期间拿到的行锁全部保留。后来的更新碰到同一批行只能等,队列越排越长。跑批脚本在循环里逐条执行又忘了 commit,事务时长直接等于整个任务时长。
「长事务持锁」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。报错里带路径的,先去看那个路径在不在、权限对不对。
SELECT trx_id, trx_started, trx_rows_locked, trx_mysql_thread_id FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 3;
同一份配置存在多处的,先确认改的是被加载的那一份。新版本先放一台机器上跑一天再全量,问题一般在这段时间暴露。
具体做法是,查 innodb_trx 找出运行最久且状态为 RUNNING 的事务;用 trx_mysql_thread_id 对上 processlist 里的连接 确认是哪个应用;kill 之前先看它改了哪些行 评估回滚代价;把跑批改成每 1000 行提交一次。
最后用这个标准收尾,最长的 trx_started 回到几秒以内 排队消失 接口 P99 从 30 秒降到 200 毫秒。
