事务回滚慢主因是sort_buffer_size不足触发out of sort memory后应用主动回滚,或innodb_buffer_pool_size不当致undo log频繁换入换出;需查错误日志、explain执行计划及innodb status定位真实瓶颈。

事务回滚慢,八成不是“内存不足”本身,而是 sort_buffer_size 不足触发 Out of sort memory 错误后,应用层主动回滚;或者 innodb_buffer_pool_size 设置不当,导致 undo log 页频繁换入换出,拖慢 purge 和回滚路径。真要查,得从错误日志和执行上下文入手,不是看 free -h 就开调参。
怎么看是不是 Out of sort memory 搞的鬼
这个错误会直接暴露在客户端或应用日志里,不是 MySQL 内部静默失败:
- Spring/MyBatis 日志中出现
java.sql.SQLException: Out of sort memory, consider increasing server sort buffer size - MySQL 错误日志(如
/var/log/mysql/error.log)里有明确的Out of sort memory; increase sort_buffer_size -
SHOW VARIABLES LIKE 'sort_buffer_size'查到值偏小(比如默认 256K),但并发连接多时,每个连接独占一份,容易挤爆物理内存
为什么不能一上来就调大 sort_buffer_size
盲目调大会掩盖真实问题,还可能引发系统级 OOM:
-
sort_buffer_size是 per-connection 分配的,设成 8M、200 个活跃连接就吃掉 1.6GB,远超单条查询实际所需 - 如果
EXPLAIN显示 SQL 有Using filesort,说明根本没走索引排序——调缓冲只是把崩溃点往后推,不是解决 - 真正该做的是:给
ORDER BY字段建联合索引(注意顺序和方向),并确认WHERE条件能有效过滤数据量
怎么判断是 undo 积压还是 IO 卡住回滚
回滚慢的根因往往不在内存总量,而在 undo 处理链路卡顿:
- 跑
SHOW ENGINE INNODB STATUS\G,找History list length:超过 5000 就说明 purge 跟不上,undo 积压严重 - 查
information_schema.INNODB_TRX,看TRX_ROWS_MODIFIED和TRX_STARTED:改了几十万行、开了十几分钟的事务,就是回滚主力 - 用
iostat -x 1看磁盘await > 20ms且%util == 100%:说明回滚正在抢 IO,不是配置问题,是硬件或负载问题
最容易被跳过的致命检查项
别漏掉 innodb_force_recovery 是否误开:
- 如果之前数据库崩溃过,有人手动加过
innodb_force_recovery = 1~6启动参数,InnoDB 会跳过 undo log 解析 - 结果就是回滚报
Unknown error或直接静默失败,看起来像“卡死”,其实是被跳过了 - 查命令:
SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'innodb_force_recovery';,非 0 就得警惕











