mysql如何优化大规模数据导入时的索引开销_mysql临时禁用索引

2次阅读

mysql如何优化大规模数据导入时的索引开销_mysql临时禁用索引

为什么导入前删索引比禁用更可靠

mysql 没有真正意义上的“临时禁用索引”机制(DROP INDEXDISABLE KEYS 仅对 MyISAM 有效,InnoDB 完全不支持)。很多人试过 ALTER table ... DISABLE KEYS,结果发现对 InnoDB 表毫无作用,甚至报错 Error 1031 (HY000): Table storage engine for 't' doesn't have this option。这不是操作姿势问题,是引擎限制。

实际可行路径只有两条:删索引再重建,或从一开始就不用建索引。前者更可控,后者适合纯 etl 场景。

  • DROP INDEX 后导入,再 CREATE INDEX,能避免每行插入都触发 B+ 树分裂和排序
  • 唯一索引(UNIQUE KEY)不能靠 DISABLE KEYS 绕过约束检查,删了才能跳过重复校验开销
  • 如果表已有大量数据,ALTER TABLE ... ADD INDEX 在导入后执行,MySQL 5.7+ 会自动用 sort-based 算法,比边插边建快 3–5 倍

批量导入时如何保留主键但跳过二级索引

主键(聚簇索引)无法删除,但二级索引可以按需剥离。关键是识别哪些索引真正在拖慢导入——通常是 created_atstatususer_id 这类高频查询字段的单列索引,而非联合索引本身。

执行前先查清楚要动哪些索引:SHOW INDEX FROM orders WHERE Key_name != 'PRIMARY';

  • DROP INDEX idx_status ON orders; 逐个删二级索引,别用 ALTER TABLE orders DROP KEY ... 别名写法,容易误删
  • 导入完成后再用 CREATE INDEX idx_status ON orders(status); 重建,注意字符集和排序规则要和原索引一致(比如 utf8mb4_0900_as_cs
  • 如果原索引带 COMMENTVISIBLE 属性,重建时得手动补上,否则应用层 ORM 可能读不到元数据

LOAD DATA INFILE 导入前必须调的三个参数

即使删了索引,LOAD DATA INFILE 默认仍可能被日志、缓冲、锁机制拖慢。这三个参数不调,吞吐量卡在 2k 行/秒左右;调完轻松上 2w+ 行/秒(SSD + 16G 内存环境)。

  • 关掉唯一检查:SET unique_checks = 0; —— 否则每行都要扫二级索引判断冲突
  • 关掉外键检查:SET foreign_key_checks = 0; —— 避免每次插入都去关联表查约束
  • 加大日志缓冲:SET innodb_log_buffer_size = 64*1024*1024;(64MB),防止频繁刷 log buffer

注意:这些是会话级设置,只对当前连接生效,导入完记得恢复:SET unique_checks = 1; SET foreign_key_checks = 1;

重建索引时最耗时的其实是统计信息更新

很多人以为 CREATE INDEX 花的时间全是建树,其实大头在最后一步:InnoDB 自动触发 ANALYZE TABLE 更新统计信息。对于亿级表,这步可能比建索引还慢,且阻塞 DML。

可以跳过它:CREATE INDEX idx_user ON orders(user_id) ALGORITHM=INPLACE, LOCK=NONE;(MySQL 5.6+),但必须加 STATS_AUTO_RECALC=0 才真正生效:

  • 先执行:ALTER TABLE orders STATS_AUTO_RECALC=0;
  • 再建索引
  • 之后手动跑一次 ANALYZE TABLE orders;(选低峰期)

漏掉 STATS_AUTO_RECALC=0,建完索引瞬间就会触发统计更新,前面所有优化白做

text=ZqhQzanResources