临时调大sort_buffer_size和read_rnd_buffer_size能显著加快大表建索引速度,但仅在退回到“拷表+排序”路径时生效;ALGORITHM=INPLACE成功时该参数无效,且必须满足SSD临时目录、高选择性字段等前提。

直接结论:临时调大 sort_buffer_size 和 read_rnd_buffer_size 能显著加快大表建索引速度,但必须配合 SSD 临时目录、避免低选择性字段,并且只对“退回到拷表+排序”路径有效。
为什么调 sort_buffer_size 有时没用
不是所有 ALTER TABLE ADD INDEX 都走排序。MySQL 5.6+ 默认优先尝试 ALGORITHM=INPLACE,如果成功,就直接在原表上构建 B+ 树,不依赖 sort_buffer_size;一旦失败(比如索引列含 TEXT、或 innodb_online_alter_log_max_size 不够),就会 fallback 到“全表扫描 → 排序 → 写新索引”的路径——这才是 sort_buffer_size 起作用的场景。
- 执行前先确认是否真进了排序路径:
SHOW PROCESSLIST看状态是否卡在Sorting for index或Creating index - 查
SHOW GLOBAL STATUS LIKE 'Sort_merge_passes':建索引前/后该值猛增,说明确实在做磁盘归并 - 如果
EXPLAIN FORMAT=JSON显示建索引语句本身用了Using filesort,那基本是误判——建索引语句不会触发查询层排序
怎么安全地临时调高 sort_buffer_size
它是个会话级变量,调错只影响当前连接,但盲目设大会吃光内存。重点不是“设多大”,而是“怎么设才稳”:
- 先查当前值:
SELECT @@sort_buffer_size(单位字节),常见默认是 262144(256KB) - 推荐起手值:
SET SESSION sort_buffer_size = 8388608(8MB),比默认大 32 倍,但仍在安全边界内 - 必须同步调
read_rnd_buffer_size到同量级:SET SESSION read_rnd_buffer_size = 8388608,否则排序完回表取主键时又卡磁盘 - 别在
my.cnf里改全局值——高并发下每个连接都占 8MB,100 个连接就是 800MB,空闲连接也锁内存 - 建完立刻恢复:
SET SESSION sort_buffer_size = DEFAULT,避免后续普通查询被拖慢
容易被忽略的三个硬性前提
调缓冲区只是加速“排序”这一步,但整个建索引流程还卡在其他地方:
-
tmpdir必须在 SSD 上且剩余空间 ≥ 表大小 × 1.5:排序临时文件可能膨胀到这个量级,SHOW VARIABLES LIKE 'tmpdir'查路径,别让它落在系统盘或满载盘 - 索引列本身要有区分度:如果
ADD INDEX的是gender或status这类只有 2–3 个值的字段,再大缓冲区也没用——这种索引本就不该存在,建了反而拖慢写入 - 确认引擎和版本支持:MySQL 5.6+ InnoDB 才支持
ALGORITHM=INPLACE;若用 MyISAM,根本不用sort_buffer_size,它走的是myisam_sort_buffer_size
更快的替代方案:绕过排序
如果调缓冲区效果仍不明显,或者你无法控制 tmpdir 磁盘类型,直接换路径更可靠:
- 强制走拷表但允许并发读:
ALTER TABLE t ADD INDEX idx_col (col) ALGORITHM=COPY, LOCK=NONE; - 前提是:InnoDB 引擎、无全文索引、
innodb_online_alter_log_max_size足够(默认 128MB,千万行表通常够) - 此时不排序,而是边读原表边插入索引树,内存压力平缓,耗时更可预期(SSD 上每百万行约 30–90 秒)
- 注意:
ALGORITHM=COPY会多占一倍磁盘空间,操作前确保datadir有余量
真正卡住的往往不是参数数字,而是没意识到排序只是建索引链条中的一环——磁盘 IO、字段选择性、引擎限制,任何一个没对齐,调再大的 sort_buffer_size 都只是给瓶颈换个位置。


















