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/并行分片,把百万插入从"一条条插"变成"批量刷",性能提升几十倍。