MySQL 8.0.27+ 二级索引创建真正并行需同时配置 innodb_ddl_threads(设为CPU物理核数,如16)、innodb_ddl_buffer_size(按线程数×100MB配,如1.6GB)和可选的 innodb_parallel_read_threads(建议同值),三者缺一不可;主键变更、虚拟列/全文/空间索引等不支持并行。

MySQL 8.0.27+ 的二级索引创建可以真正并行,但必须同时调优 innodb_ddl_threads、innodb_ddl_buffer_size 和(可选)innodb_parallel_read_threads,缺一不可;主键变更、虚拟列索引、全文索引等均不支持并行。
确认你的 ALTER TABLE 确实走并行 DDL 路径
不是所有 ALTER TABLE ADD INDEX 都能并行。只有满足以下全部条件时,InnoDB 才会启用多线程构建二级索引:
- MySQL 版本 ≥ 8.0.27(推荐 8.0.30+)
- 目标是普通二级索引(不含
VIRTUAL列、FULLTEXT或SPATIAL) - 未使用
ALGORITHM=COPY(该模式强制单线程) - 表引擎为 InnoDB,且非临时表、分区表
-
innodb_ddl_threads > 1且innodb_ddl_buffer_size已同步放大
常见误判:看到 SHOW PROCESSLIST 显示 altering table 就以为卡住——其实可能正在并行扫描或排序,只是没进度反馈。别靠“不动”判断慢,要靠耗时对比和参数验证。
必须配齐的三个参数及其合理取值
这三个参数是硬性组合,单独调高某一个基本无效,甚至拖慢:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
-
innodb_ddl_threads:控制排序 + B+ 树构建阶段的并发线程数。默认 4,建议设为 CPU 物理核数(如 16 核设 12–16),但不要超过 32 —— 多了易引发锁竞争和上下文切换开销 -
innodb_ddl_buffer_size:所有 DDL 线程共用的总排序缓冲区。默认仅 1MB,对千万级表远远不够。必须按比例放大:innodb_ddl_buffer_size = innodb_ddl_threads × 100MB是较稳妥起点(例如 16 线程 → 至少 1.6GB)。实测中 1GB 配 8 线程比 100MB 配 8 线程快近 2 倍 -
innodb_parallel_read_threads:影响聚簇索引扫描阶段的读取并发度。它不决定最终是否并行建索引,但能加速“读数据→写排序文件”这一步。建议与innodb_ddl_threads同值(如都设 8),但设低些(如 4)也常够用;设太高反而抢内存
注意:innodb_parallel_read_threads 对 DDL 的加速效果远弱于前两者,优先保 innodb_ddl_threads 和 innodb_ddl_buffer_size 的匹配。
为什么调了参数还是没变快?常见踩坑点
并行 DDL 不是“设完就飞”,大量实际案例失败源于忽略底层约束:
- 磁盘 I/O 成瓶颈:SSD 上
iostat -x 1中await > 20ms或%util > 95%时,并行只会加剧排队。先优化存储,再谈并行 - 长事务阻塞 prepare 阶段:DDL 开始前需加 MDL 锁,
SELECT * FROM performance_schema.data_lock_waits可查谁在 hold 表锁 - change buffer 合并压力大:机械盘环境建议临时执行
SET GLOBAL innodb_change_buffering = 'none',避免建索引时触发巨量合并 - buffer pool 污染严重:大表扫描挤出热数据,导致后续查询抖动。可考虑在低峰期操作,或提前预热关键页
- 统计信息陈旧:建完索引后
EXPLAIN仍走全表扫描?先ANALYZE TABLE更新统计信息
最常被忽略的一点:并行只加速“排序”和“B+ 树加载”,不加速“读主键数据”本身。如果表字段极大(含大量 TEXT)、或 WHERE 条件筛选率极低,并行归并开销可能抵消收益——这时宁可降线程数,稳中求快。










