重建索引是停机时间大头,因mysql默认单线程逐条插入建索引,i/o与cpu压力高;8000万行建二级索引需2–5小时,远超数据拷贝耗时。

为什么重建索引是停机时间的大头
迁移大表时,真正卡住切换窗口的往往不是数据拷贝,而是最后一步 ALTER TABLE ... ADD INDEX。MySQL 在已有大量数据的表上建索引,默认走单线程 B+ 树插入:每条记录都要定位页、分裂页、更新父节点,I/O 和 CPU 压力都极高。8000 万行的表建一个二级索引,可能耗时 2–5 小时——这直接把“停写窗口”从秒级拉到小时级。
先灌数据再建索引,别边插边建
这是最有效、最易落地的提速手段。核心逻辑是让 MySQL 用排序构建(sorted index build)替代逐条插入,效率能提升 3–10 倍。
- 迁移前执行
SET unique_checks = 0和SET autocommit = 0,避免每行都校验唯一性、触发日志刷盘 - 用
INSERT INTO new_table SELECT * FROM old_table一次性灌入,而不是逐行INSERT - 等所有数据写完再统一建索引,多个索引尽量合并进一条
ALTER TABLE,例如:ALTER TABLE t ADD INDEX idx_a (a), ADD INDEX idx_b (b) - 建完立刻执行
SET unique_checks = 1和COMMIT
用 pt-online-schema-change 替代手工建索引
当业务完全不能接受任何锁表(哪怕只读锁),或者你无法控制迁移流程(比如没权限改全局变量),pt-online-schema-change 是更稳妥的选择。它不依赖“先空表后灌数据”,而是在原表旁建影子表、用触发器同步增量、分 chunk 拷贝并在线建索引。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
- 它建索引的过程本身仍是后台异步的,不会阻塞主表 DML
- 必须确保原表有主键或唯一非空索引,否则无法分片
- 命令示例:
pt-online-schema-change --alter "ADD INDEX idx_status (status)" D=app,t=orders --execute - 注意磁盘空间要预留 2 倍——影子表 + 原表 + 日志
别忽略字符集和排序规则对索引生效的影响
CREATE TABLE AS SELECT 不继承原表的 CHARACTER SET 和 COLLATE,如果新表用了默认 utf8mb4_0900_as_cs 而原表是 utf8mb4_unicode_ci,即使字段名、类型一样,索引也可能因排序规则不一致而无法命中查询条件。
- 务必用
SHOW CREATE TABLE old_table提取完整建表语句,手动复制DEFAULT CHARSET和COLLATE - 检查
INFORMATION_SCHEMA.STATISTICS确认索引列的COLLATION字段值是否与原表一致 - 若已建错,只能
DROP INDEX后用正确COLLATE重建
重建索引快慢,表面看是参数和工具的事,实际取决于你有没有在建表那一刻就锁定字符集、有没有在灌数据前关掉唯一性检查——这些细节一旦漏掉,后面花再大力气优化也补不回那几十分钟。










