大批量导入数据时应先删除索引(主键需特殊处理)、禁用外键和唯一性检查,导入后再按顺序重建索引并恢复检查,可提速3–5倍;innodb不支持disable keys,该命令仅对myisam有效。

导入前删索引,导入完再重建最省时间
大批量导入时保留索引会严重拖慢速度,因为每插入一行都要更新所有相关索引树。实测 100 万行数据,带主键+2个普通索引的表,边插边建索引比先删后建慢 3–5 倍。关键是:不是“慢一点”,是慢到可能超时或锁表太久。
-
DROP INDEX比ALTER TABLE ... DISABLE KEYS更彻底,后者只对MyISAM有效,InnoDB必须用删索引 - 主键不能删,但可以先
ALTER TABLE ... DROP PRIMARY KEY(需同时指定新主键,比如转成ADD PRIMARY KEY (id)后再删,实际常用临时去掉auto_increment+ 重建) - 外键约束必须先禁用:
SET FOREIGN_KEY_CHECKS = 0,否则删索引可能被拦住 - 删完记得记下索引定义,用
SHOW CREATE TABLE备份,别靠脑子记
用 LOAD DATA INFILE 配合禁用唯一性检查
比 INSERT 批量语句快一个数量级,但默认仍校验唯一约束和外键。不关掉,它会在每行都查索引——这正好是我们刚删掉的东西,反而触发全表扫描补漏。
- 导入前执行:
SET UNIQUE_CHECKS = 0和SET FOREIGN_KEY_CHECKS = 0 - 导入命令里加
LOCAL关键字(如果从客户端文件导入):LOAD DATA LOCAL INFILE '/path/data.csv' INTO TABLE t1 - 导入后立刻开回检查:
SET UNIQUE_CHECKS = 1,然后马上ALTER TABLE ... ADD INDEX,否则后续查询可能因缺失索引而变慢 - 注意:MySQL 8.0+ 默认关闭
LOCAL INFILE,服务端要开local_infile=ON,客户端连接也要加--local-infile
ALTER TABLE ... DISABLE KEYS 只对 MyISAM 有用
很多人搜到这个命令就直接套用,结果在 InnoDB 表上执行完全没效果——它只是个空操作,SHOW PROCESSLIST 里也看不到任何变化。InnoDB 的索引更新机制和存储结构决定了它不支持这个开关。
-
DISABLE KEYS/ENABLE KEYS是 MyISAM 特有的优化手段,仅影响非唯一索引构建 - InnoDB 下强行执行不会报错,但也不会提速,反而可能让人误以为“已经优化过了”
- 验证方法:导入过程中看
information_schema.INNODB_METRICS里的dml_inserts和index_page_splits,如果后者持续上涨,说明索引仍在实时更新
重建索引顺序影响最终性能
不是所有索引重建都一样快。B+ 树构建效率高度依赖数据有序程度,而导入数据通常按主键递增(尤其自增 ID),所以重建顺序要顺着这个“天然序”来。
- 先建主键(如果刚删过,用
ADD PRIMARY KEY (id))——这是聚簇索引,决定物理排序 - 再建与主键字段顺序一致的联合索引,比如
(user_id, created_at),如果数据本身按user_id分组写入,能减少页分裂 - 最后建高选择性但无序的单列索引,比如
email,这类重建最耗时,放最后避免阻塞其他操作 - 避免在重建中途做
ANALYZE TABLE,统计信息会自动更新,手动触发反而多一次 I/O
真正卡住的往往不是导入本身,而是重建索引时磁盘随机写太多、buffer pool 被冲垮、或者忘了开回 UNIQUE_CHECKS 导致后续 INSERT 报错。留 20% 时间专门盯 SHOW ENGINE INNODB STATUS 里的 ROW OPERATIONS 和 LOG 段,比反复重试管用。











