Skip to content

P18 SpringBoot 如果有百万数据插入怎么优化 ​

面试题:向 MySQL 批量插入百万条数据(如初始化数据/导入),怎么优化?

核心:批量 + 减少开销 ​

1. 批量插入(一条 SQL 多 values) ​

不要一条条 INSERT,用批量拼接:

sql
INSERT INTO t (a, b) VALUES (1,2),(3,4),(5,6)...;

每批 500~2000 条,减少 SQL 解析和网络往返。

2. JDBC 层面 ​

  • rewriteBatchedStatements=true(MySQL JDBC 关键参数),让 addBatch 真正合并成多 values 一次发送:
yaml
jdbc:mysql://host:3306/db?rewriteBatchedStatements=true
  • 关闭自动提交,手动分批 commit;
  • 用 PreparedStatement 预编译复用。

3. 事务控制 ​

  • 每批一个事务(如 5000 条 commit 一次),避免超大事务(锁持有久、undo 膨胀、主从延迟大);
  • 不要整个 100 万条一个事务。

4. 索引与约束 ​

  • 插入前先删非唯一索引,插完再重建(索引维护开销大);
  • 唯一约束有冲突检查开销,能去重先做;
  • 大表可临时禁用/合并外键检查(SET FOREIGN_KEY_CHECKS=0,生产慎用)。

5. 其他手段 ​

  • 用 Load Data Infile:MySQL 原生批量导入,比 INSERT 快几个数量级(适合离线导入);
  • 并行写入:多个线程/连接分片并发插入(注意行锁竞争和主从延迟);
  • 分库分表:数据量大时按业务键分片;
  • 异步化:数据导入走 MQ 异步消费,不阻塞主流程。

加分点 ​

  • 提前把数据去重、排序(按主键排序插入减少页分裂);
  • 观察 innodb_buffer_pool_size 和磁盘 IO,插入是 IO 密集操作;
  • 生产导入用灰度 + 限速,避免影响线上业务。

一句话总结 ​

批量多 values + rewriteBatchedStatements=true + 分批事务 + 临时精简索引 + Load Data/并行分片,把百万插入从"一条条插"变成"批量刷",性能提升几十倍。

基于 VitePress 重建