mysql中批量插入数据时的性能优化技巧

11次阅读

应优先使用多值INSERT、事务包裹、禁用约束检查及LOAD DATA INFILE。单条插入1000次比单条多值插入慢10倍以上;建议每批≤1000行,配合SET autocommit=0、BEGIN/COMMIT;可设unique_checks=0、foreign_key_checks=0提速,但须恢复;LOAD DATA INFILE最快,比INSERT快20倍以上。

mysql中批量插入数据时的性能优化技巧

用 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_checksforeign_key_checks 关了没恢复,或者 max_allowed_packet 不够导致批量语句被截断 —— 这类问题不会报错,只会静默失败几行数据。

text=ZqhQzanResources