结论:别全局硬塞sort_buffer_size,优先用set session临时调,256kb~4mb是安全区间;调完必须验证是否真触发using filesort,否则纯属浪费内存。

直接说结论:别全局硬塞 sort_buffer_size,优先用 SET SESSION 临时调,256KB~4MB 是安全区间;调完必须验证是否真触发了 Using filesort,否则纯属浪费内存。
怎么确认真需要调 sort_buffer_size
MySQL 只在无法走索引排序时才分配这个 buffer,不是所有 ORDER BY 都会用它。
- 先跑
EXPLAIN SELECT ... ORDER BY ...,看Extra列是否出现Using filesort - 如果
type是index或range,但仍有Using filesort,说明索引没覆盖排序字段(比如缺复合索引、字段太长如VARCHAR(2000)) - 字段类型是
TEXT或超长VARCHAR,即使建了索引,InnoDB 也可能退化为 filesort - 没出现
Using filesort却去调大sort_buffer_size,只会放大内存压力,毫无收益
为什么改了配置文件却没生效
常见现象:改了 my.cnf 里的 sort_buffer_size,重启 MySQL 后 SHOW VARIABLES LIKE 'sort_buffer_size' 还是旧值。
Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
- 你改的是全局变量,但已有连接继承的是启动时的会话值;新连接才会读取新全局值——必须重启客户端连接,或手动执行
SET SESSION sort_buffer_size = 4194304 - 某些中间件(如 ProxySQL、ShardingSphere)或 ORM(如 Django 的
connection.cursor())会显式重置会话变量,覆盖你设的全局值 - MySQL 8.0.22+ 起,
sort_buffer_size不支持SET GLOBAL动态修改,只能写进配置文件并重启 - 检查
my.cnf是否多处定义(比如[mysqld]和[client]段都写了),后者无效
sort_buffer_size 设多大才不翻车
它是 per-connection 的独占内存,不是共享池,设高了极易 OOM。
- 默认值通常是
262144(256KB),对多数 OLTP 查询已够用 - 万级行排序可试
1048576~4194304(1MB~4MB);超过8388608(8MB)极少必要,反而加剧内存碎片 - 线上建议先用
SET SESSION sort_buffer_size = 4194304临时设置,仅对当前查询生效,避免污染其他连接 - 别全局设太高——100 个并发 × 8MB = 800MB 静态占用,但实际可能只有 5% 连接真用到它
- 查当前负载:运行
SHOW GLOBAL STATUS LIKE 'Sort_merge_passes',数值持续上升才说明频繁磁盘排序
和 read_rnd_buffer_size 到底谁该动
这两个常被混用,但职责完全不同,不能瞎调一气。
-
sort_buffer_size管排序阶段内存;read_rnd_buffer_size管排序完回表取数据时的随机读缓冲 - 先看
EXPLAIN输出:有Using filesort就优先调sort_buffer_size;若还有Using temporary,再考虑两者都检查 - 只有当执行计划同时出现
Using filesort和Using where(或Using index condition),且排序字段不在索引中时,read_rnd_buffer_size才可能成为瓶颈 -
read_rnd_buffer_size默认通常比sort_buffer_size小(比如 256KB vs 2MB),也按连接分配,同样禁不住无脑拉高
真正难的不是设数字,而是判断「这查询到底有没有走 filesort」——很多 DBA 调了半天,发现 EXPLAIN 里压根没 Using filesort,纯属白忙活。索引设计不到位,光调 buffer 没用。










