先查错误日志确认是否含“out of sort memory”,排除query execution was interrupted等干扰项;再用explain看执行计划,重点检查using filesort;同时验证json等大字段是否撑爆缓冲,检查tmpdir磁盘空间及连接数是否失控。

确认错误是否真由排序内存不足触发
别一看到Sort aborted: Out of sort memory就调参数。先查 MySQL 错误日志(通常是 /var/log/mysql/error.log 或 mysqld.err),确认报错完整信息里是否含 Out of sort memory,而不是 Query execution was interrupted 或 Server shutdown in progress——后者说明是超时、KILL 或主动关库,和内存无关。
同时检查应用层日志:Spring 项目若抛出 java.sql.SQLException: Out of sort memory,才真正对应这个瓶颈;如果只是事务回滚但没这句异常,大概率是 OOM Killer 杀了 mysqld 进程,得去系统日志(dmesg -T | grep -i "killed process")里找证据。
用 EXPLAIN 快速定位是否走了 filesort
EXPLAIN 是比改配置更有效的诊断工具。对报错 SQL 执行 EXPLAIN SELECT ... ORDER BY ...,重点看 Extra 列:
- 出现
Using filesort→ 没走索引排序,必须优化索引 - 出现
Using temporary; Using filesort→ 同时触发临时表 + 文件排序,问题更重 - 即使
rows很小,只要Using filesort存在,sort_buffer_size就可能被大字段撑爆(比如 JSON 字段在 MySQL 8.0.20+ 默认进排序缓冲)
注意:MySQL 8.0 支持降序索引,ORDER BY created_at DESC, id ASC 要建 INDEX(created_at DESC, id ASC) 才能完全覆盖,只建 (created_at, id) 可能仍触发 filesort。
检查是否因大字段(如 JSON)导致缓冲区瞬间溢出
MySQL 8.0.20 起,JSON 和 GEOMETRY 字段在排序时默认以 packed addons 方式加载进 sort_buffer_size,哪怕只取 10 行,单条 JSON 值几 MB 就会直接冲垮默认 256KB 缓冲。
验证方法:
- 把原 SQL 的
SELECT *或含 JSON/BLOB 的字段精简掉,比如改成SELECT id, created_at FROM t WHERE ... ORDER BY created_at DESC LIMIT 20,再执行——如果不再报错,就是字段拖累 - 用
SHOW VARIABLES LIKE 'sort_buffer_size'查当前值,再估算:单条 JSON 平均大小 × 排序行数 >sort_buffer_size→ 铁定溢出
此时加索引或删字段比调参管用得多;盲目设成 4M,100 个并发就吃掉 400MB,还可能触发 mmap 分配拖慢性能。
别忽略 tmpdir 磁盘空间和连接数失控
Sort aborted 不一定全是内存问题。两个常被跳过的点:
-
tmpdir路径磁盘满:MySQL 在内存不够时会落盘排序,df -h $(mysql -Nse "SELECT @@tmpdir")必须检查,尤其是 Docker 容器里默认用/tmp,容易被其他进程占满 - 连接数远超预期:
sort_buffer_size是每个连接独占,max_connections = 1000且设为 2M,光这一项理论峰值就 2GB;用ps -o pid,rss,comm -C mysqld看实际 RSS 内存,若远超所有 buffer 参数之和,大概率有连接泄漏或未关闭的长事务
真正棘手的是组合问题:没索引 + JSON 字段 + tmpdir 满 + 高并发连接——这时候调任何一个参数都只能让崩溃来得稍晚一点。











