sort_buffer_size设太小会导致建索引卡在sorting for table状态:因键值无法全存入内存,频繁磁盘归并,i/o激增;千万级表建议设2mb–16mb,并用set session动态调整。

sort_buffer_size设太小会导致建索引卡在Sorting for table状态
MySQL 创建 B-tree 索引时,若需排序(比如 ALTER TABLE ADD INDEX),会把键值暂存在 sort_buffer_size 中。默认值通常只有 256KB,对百万级以上表基本不够用——结果就是频繁写临时磁盘文件、反复归并,SHOW PROCESSLIST 里长时间卡在 Sorting for table,耗时翻倍甚至更糟。
实操建议:
- 先确认当前值:
SELECT @@sort_buffer_size;(单位字节) - 对千万行表,可尝试设为
2MB~16MB(即2097152~16777216) - 必须用会话级设置:
SET SESSION sort_buffer_size = 8388608;,避免影响其他连接 - 并发建索引时,总内存占用 = 并发线程数 × 该值,务必留足给
innodb_buffer_pool_size
别碰innodb_doublewrite,它不加速索引构建
有人误以为关掉 innodb_doublewrite 能“减少写入开销”从而加快建索引,这是典型误解。双写缓冲区只负责防止部分写入损坏页,不参与排序、不缓存索引键、也不影响 B+ 树分裂路径——关了它,建索引速度不变,但崩溃后大概率无法启动。
真正拖慢索引写入的环节是:
-
innodb_buffer_pool_size不足 → 频繁换页、读旧页 -
sort_buffer_size过小 → 排序落盘 -
innodb_log_file_size太小 → redo log 频繁 checkpoint - 磁盘 IO 瓶颈(尤其临时文件目录所在设备)
TEMPTABLE 引擎比 MEMORY 更适合建索引时的临时表
建索引过程中,MySQL 可能生成内部临时表(比如 GROUP BY 或 DISTINCT 场景)。设 internal_tmp_mem_storage_engine = MEMORY 看似“纯内存”,但遇到 TEXT/BLOB 或超 max_heap_table_size 就直接报错 ERROR 1114;而 TEMPTABLE(MySQL 8.0 默认)支持按页落盘,更稳。
关键配置组合:
- 显式设:
SET SESSION internal_tmp_mem_storage_engine = TEMPTABLE; - 调大内存上限:
SET SESSION temptable_max_ram = 1073741824;(1GB) - 同步设:
SET SESSION tmp_table_size = 268435456;和SET SESSION max_heap_table_size = 268435456;(256MB,且 ≤temptable_max_ram) - 验证是否生效:执行建索引前的复杂查询后,查
SHOW STATUS LIKE 'Created_tmp%';,关注Created_tmp_disk_tables增速是否明显下降
innodb_ddl_threads > 1 才可能触发二级索引并行构建
MySQL 8.0.27+ 支持多线程构建二级索引,但默认关闭。仅靠调大 innodb_sort_buffer_size 不足以激活并行——必须显式设 innodb_ddl_threads(默认是 4,但需确认版本是否 ≥ 8.0.27)。
注意事项:
- 只对二级索引有效,主键重建仍是单线程
- 不支持虚拟列、FULLTEXT、SPATIAL 索引
- 数据重复率高或 WHERE 过滤率低时,并行反而可能因归并开销变慢
- 线上调高前,先在测试环境跑
ALTER TABLE t ADD INDEX idx_x (x);对比耗时
sort_buffer_size = 16MB,再加 temptable_max_ram = 1GB,再加上 innodb_buffer_pool_size 占用,很容易挤爆物理内存。别只盯着单个参数,得算总账。











