上一篇
场景引入:
凌晨3点,程序员小张盯着屏幕上的进度条崩溃了——50万条数据导了半小时还没完!😫 隔壁组用同样配置的服务器,10分钟就搞定了,问题出在哪?今天我们就拆解「批量写入慢」的元凶,并送上亲测有效的优化方案!
// 反面教材:循环单条插入 for (User user : userList) { userMapper.insert(user); // 每条都单独连接、执行、提交 }
💡 问题:每条SQL都经历网络传输、语法解析、事务提交,就像快递员每次只送一个包裹📦,90%时间浪费在来回路上!
默认自动提交事务(autocommit=true
)时,数据库每插入一条就刷一次磁盘日志💾,想象一下:写日记每写一个字就合上一次本子,手酸不酸?
表上有5个索引?每次插入数据时,数据库要同步更新所有索引🌲,就像搬家时非要同时整理衣柜、书柜、鞋柜,能不慢吗?
配置的连接池只有5个?100个线程抢5个连接,排队等到天荒地老...🚦
INSERT INTO users (name,age) VALUES ('张三',25); INSERT INTO users (name,age) VALUES ('李四',30); ...
每条SQL都被数据库重新解析,相当于每道数学题都重新学一遍公式✖️
// MyBatis Plus示例 userService.saveBatch(userList, 5000); // 每5000条批量提交一次 // JDBC批处理 Connection conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement("INSERT INTO users..."); for (User user : userList) { ps.setString(1, user.getName()); ps.addBatch(); // 加入批处理 if (i % 1000 == 0) ps.executeBatch(); // 每1000条执行一次 }
📈 效果:实测10万条数据从120秒→3秒!
@Transactional // Spring事务注解 public void batchInsert(List<User> list) { userMapper.batchInsert(list); // 整个列表作为一个事务 }
💡 关键:确保单次批量操作在一个事务内,避免频繁提交。
-- MySQL示例 ALTER TABLE users DISABLE KEYS; -- 执行批量插入... ALTER TABLE users ENABLE KEYS;
⚠️ 注意:适合百万级以上数据迁移,线上业务慎用!
# SpringBoot配置示例 spring: datasource: hikari: maximum-pool-size: 50 # 根据服务器CPU核心数调整 connection-timeout: 30000
📌 建议:连接数 ≈ CPU核心数 × 2 + 磁盘数(SSD可适当增加)
-- 一条SQL插入多行 INSERT INTO users (name, age) VALUES ('张三', 25), ('李四', 30), ... -- 建议每批500-2000行
// Java并行流示例(CPU密集型慎用) userList.parallelStream() .forEach(batch -> splitAndInsert(batch));
⚡ 配合连接池+批量插入,速度再翻倍!
方案 | 10万条耗时 | 适用场景 |
---|---|---|
单条插入 | 120s | 绝对不要用! |
批量+事务 | 3s | 常规推荐✅ |
禁用索引+批量 | 8s | 数据迁移专用 |
并行批量 | 2s | 多核服务器+IO瓶颈 |
max_allowed_packet
会报错,建议每批5000-20000行 :数据库写入就像搬家,用对方法才能又快又稳!下次遇到批量插入,试试「批量+事务+连接池调优」组合拳吧~ 🥊
(注:本文测试基于MySQL 8.2、Oracle 21c,其他数据库原理类似但语法可能有差异)
本文由 旁清润 于2025-08-02发表在【云服务器提供商】,文中图片由(旁清润)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://vps.7tqx.com/wenda/511676.html
发表评论