用 INSERT ... VALUES 多值插入,别单条循环
单条
INSERT INTO table (a,b) VALUES (1,2)执行 1000 次,和一条
INSERT INTO table (a,b) VALUES (1,2),(3,4),(5,6),...,(1999,2000)执行 1 次,性能差距可达 10 倍以上。MySQL 要为每条语句做解析、权限检查、日志写入等开销,多值插入能大幅摊薄这些成本。 单次插入行数建议控制在 1000 行以内(受
max_allowed_packet限制,可查
SHOW VARIABLES LIKE 'max_allowed_packet') 避免拼接超长 SQL 导致内存溢出或网络超时;可用分批提交,比如每 500 行一组 注意:如果某一批中某一行违反唯一约束,整批会失败;需根据业务容忍度决定是否拆更小批次或加
ON DUPLICATE KEY UPDATE
关闭自动提交 + 手动事务包裹
默认开启
autocommit=1时,每条
INSERT都是一次独立事务,强制刷盘(尤其是
innodb_flush_log_at_trx_commit=1时),I/O 成为瓶颈。 显式执行
SET autocommit = 0,再用
BEGIN/
START TRANSACTION包裹批量操作,最后
COMMIT不推荐用
SET autocommit = 0后不配
COMMIT—— 连接断开会导致事务回滚,且长事务会拖慢 MVCC 清理和锁等待 若中途出错需回滚,用
ROLLBACK;但注意大事务回滚本身也耗时,建议先校验数据再提交
临时禁用唯一/外键检查与索引更新
大批量导入前,若确认数据合规,可跳过约束校验和二级索引维护,显著提速。
禁用唯一性检查:SET unique_checks = 0(导入后记得
SET unique_checks = 1,否则后续插入可能破坏唯一性) 禁用外键检查:
SET foreign_key_checks = 0(同样需恢复) 注意:禁用后不会重建索引,仅跳过插入时的校验;索引仍存在,只是暂不更新。如需彻底跳过索引构建,得用
LOAD DATA INFILE配合
DISABLE KEYS
优先用 LOAD DATA INFILE 替代 INSERT
当数据源是本地文件(如 CSV),
LOAD DATA INFILE是 MySQL 官方最高效的批量导入方式,比等量
INSERT快 20 倍以上,因它绕过 SQL 解析层,直接走存储引擎接口。
LOAD DATA INFILE '/tmp/data.csv' INTO TABLE my_table FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS;要求文件在数据库服务器本地(除非启用
local_infile=1并用
LOAD DATA LOCAL INFILE)
IGNORE 1 ROWS跳过表头;字段顺序必须与表定义严格一致,或用列名映射(如
(col_a, col_b)) 导入期间会自动禁用索引更新(
DISABLE KEYS),结束后重建,比手动关/开更快更安全 真正卡住性能的往往不是 SQL 写法本身,而是事务粒度、约束校验时机和数据落盘策略。尤其要注意
unique_checks和
foreign_key_checks关了没恢复,或者
max_allowed_packet不够导致批量语句被截断 —— 这类问题不会报错,只会静默失败几行数据。
