如何通过SQL查询将Excel数据导入MySQL?Spring Boot循环插5万行慢求优化方案
5万行以上Excel数据导入数据库的最优实现方案
原有逻辑的性能瓶颈说明
逐行循环插入的方式,慢的核心原因有两个:一是5万行数据对应5万次应用和数据库之间的网络往返,开销极高;二是逐行提交事务的刷盘成本,把整体耗时拉到分钟级甚至更长。
性能优先级最高的方案:数据库原生直读文件导入
这是所有实现方式里吞吐量最高的方案,完全跳过应用层的数据解析、内存传输环节,直接让数据库读取本地Excel/CSV文件完成写入,单库导入50万行数据仅需数秒。
不同数据库对应的实现:
- MySQL:将Excel另存为CSV格式后,开启
local_infile权限,直接执行LOAD DATA INFILE语法完成导入,示例:LOAD DATA LOCAL INFILE '/file/path/data.csv' INTO TABLE 目标表名 FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' IGNORE 1 ROWS; - SQL Server:使用
BULK INSERT或OPENROWSET命令,直接关联文件路径完成批量导入。 - PostgreSQL:使用
COPY命令直读CSV文件批量写入,吞吐量是JDBC批处理的2-3倍。
注意事项:这种方案要求导入的文件和数据库实例在网络可达的存储路径下,云数据库环境如果不支持挂载本地文件,就没法用这个方式。
次优方案:应用层真批处理改造
如果数据库是托管云实例,没有权限直接访问服务器本地文件,就改造现有Spring Boot逻辑,把假批处理改成真批处理,耗时能从十几分钟压到10秒级:
- 必须给JDBC连接串加批处理参数:MySQL连接末尾追加
rewriteBatchedStatements=true&useServerPrepStmts=false,这个参数不开的话,哪怕你用了框架的saveBatch方法,实际还是逐行发送SQL,根本没有批处理效果。 - 按固定大小分块攒数据:不要逐行读Excel逐行插,每累计1000-2000行就凑成一个执行批次,既避免一次性把5万行全塞内存导致OOM,也减少网络请求次数。
- 事务按批次统一提交:不要每插一行就提交一次事务,每个批次的插入操作放在同一个事务里执行完再统一提交,大幅减少事务刷盘的IO开销。
- Excel解析层替换:用EasyExcel的逐行读模式替代传统POI的全量加载模式,边读数据边攒批次,内存占用能降90%以上。
快速适配临时方案
如果不想大改现有代码,只要把原来的单值insert改成多值批量拼接的SQL形式,比如每1000行拼一次insert into 表(字段1,字段2) values(值1,值2),(值3,值4)...的结构,配合上面的JDBC参数,也能满足5万行数据的导入性能要求。
注意坑:不要一次性拼接几万行的values,MySQL默认的
max_allowed_packet配置通常为4M,SQL包过大会直接报写入失败。
内容的提问来源于stack exchange,提问作者Ajith
相关产品推荐
相关产品推荐

