关闭 foreign_key_checks 仅在外键存在且被触发时提速,必须配对恢复;真正瓶颈是唯一索引校验,需同时设 unique_checks=0 并在导入后恢复,否则数据不一致。

关 foreign_key_checks 能提速,但只在特定场景下有效,且必须配对恢复
为什么 SET FOREIGN_KEY_CHECKS = 0 有时没效果
这个设置只跳过外键约束校验,不跳过唯一索引、主键冲突、字段类型转换或 NULL 约束检查。如果你的表没有定义外键,或者导入数据本身不触发外键引用(比如目标表是空的、或外键列全为 NULL),那关掉它完全不会提升速度。
- 执行
SHOW CREATE TABLE your_table确认表里真有FOREIGN KEY定义 - 检查导入数据中涉及的外键字段值是否实际存在于被引用表——如果全是无效值,MySQL 会报错,
FOREIGN_KEY_CHECKS = 0也救不了 - InnoDB 表即使关了外键检查,仍要维护聚簇索引和二级索引,这部分开销不受影响
必须搭配 SET UNIQUE_CHECKS = 0 才能明显提速
外键检查只是冰山一角;真正吃性能的是唯一索引(包括主键)的逐行查找与插入校验。关掉 UNIQUE_CHECKS 后,InnoDB 会延迟构建唯一索引,直到导入结束再批量校验,省下大量 B+ 树搜索时间。
- 务必成对使用:
SET unique_checks = 0;+SET foreign_key_checks = 0; - 导入完成后立即恢复:
SET unique_checks = 1;和SET foreign_key_checks = 1;,否则后续 INSERT 可能静默失败或破坏数据一致性 - 恢复
unique_checks = 1时,MySQL 会重建所有唯一索引——这是个阻塞操作,大表可能卡住几秒到几分钟,得预留时间
LOAD DATA INFILE 下的正确用法示例
单独设变量不够,得结合文件格式与引擎行为。例如对 InnoDB 表:
SET unique_checks = 0; SET foreign_key_checks = 0; -- 如果你确定数据主键有序,还能加这句(仅限 InnoDB) SET sort_buffer_size = 256*1024*1024; <p>LOAD DATA INFILE '/var/lib/mysql-files/data.csv' INTO TABLE t1 FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS;</p><p>SET unique_checks = 1; SET foreign_key_checks = 1;</p>
注意:sort_buffer_size 是会话级变量,设太大反而可能引发内存争抢;一般 64M–256M 足够,别盲目堆到 1G。
容易被忽略的坑:autocommit 和 innodb_flush_log_at_trx_commit
即使关了外键和唯一检查,每行仍可能被当成独立事务提交——尤其是用 LOAD DATA LOCAL INFILE 且客户端未显式控制事务时。
- 导入前加
SET autocommit = 0;,导入后COMMIT;,避免日志刷盘次数爆炸 - 临时调低持久性保障:
SET GLOBAL innodb_flush_log_at_trx_commit = 2;(导入完记得改回 1) - 但要注意:设为 2 意味着崩溃可能丢失最多 1 秒事务,仅限非生产环境或可接受风险的迁移
真正卡住的往往不是外键,而是日志刷盘策略和事务粒度——这些比开关两个 checks 更影响最终耗时。











