Spring Boot+MySQL环境下ZStandard压缩大体积JSON批量导入性能优化及速度合理性咨询
你的导入速度完全不合理,而且当前代码存在多个致命瓶颈,咱们一步步来拆解和优化:
首先,先戳破核心问题:你提到文件是ZStandard(zstd)压缩的,但当前代码直接用FileReader读取——这根本不对!zstd是二进制压缩格式,FileReader读出来的是乱码,你现在的解析逻辑能跑通都奇怪(要么你实际代码里有解压步骤没贴,要么数据其实没被正确解析),这是第一个要修复的点。
接下来,咱们逐个分析瓶颈和优化方案:
1. 先解决最基础的解压问题
你需要用zstd的Java库来解压数据流,推荐用com.github.luben:zstd-jni(Maven依赖)。替换掉你的FileReader,用ZstdInputStream包裹文件输入流,再转成BufferedReader:
// 添加Maven依赖 // <dependency> // <groupId>com.github.luben</groupId> // <artifactId>zstd-jni</artifactId> // <version>1.5.5-12</version> // </dependency> // 读取压缩文件的正确方式 try (ZstdInputStream zstdIn = new ZstdInputStream(new FileInputStream("/opt/tomcat/" + fileName)); BufferedReader br = new BufferedReader(new InputStreamReader(zstdIn))) { // 后续处理逻辑 }
2. 消除代码里的低效操作
你的当前代码有两个超级浪费的点:
- 重复反序列化JSON:每次循环调用两次
om.readValue(line, Data.class),完全可以解析一次存起来复用。 - 单条数据库操作+同步查询:每次循环都查一次
existsByAddress,再单条save,数据库IO是最大的瓶颈。
优化步骤:
a. 批量加载现有address到内存,避免重复查询
先把数据库里所有已存在的address拉到一个HashSet里,这样判断是否存在直接在内存查,速度快几个数量级:
// 提前加载所有已存在的address(如果数据量过大,可分批加载,但30GB的JSON对应的address数量如果不是亿级,内存应该能扛) Set<String> existingAddresses = new HashSet<>(rootRepository.findAllAddresses()); // 这里需要你在Repository里加一个自定义方法:List<String> findAllAddresses();
b. 批量收集待插入数据,批量写入数据库
不要单条save,而是收集到一个列表,达到阈值(比如1000条)就批量插入:
ObjectMapper om = new ObjectMapper(); List<Data> batchData = new ArrayList<>(1000); String line; while ((line = br.readLine()) != null) { Data data = om.readValue(line, Data.class); if (!existingAddresses.contains(data.getAddress())) { batchData.add(data); // 达到批量阈值就写入 if (batchData.size() >= 1000) { rootRepository.saveAll(batchData); batchData.clear(); } } } // 处理剩余的最后一批数据 if (!batchData.isEmpty()) { rootRepository.saveAll(batchData); }
3. 进阶优化:利用多线程提升处理速度
单线程处理30GB数据肯定慢,用生产者-消费者模式,让解压、解析、写入分开在不同线程执行:
- 生产者线程:负责解压读取行数据,放到阻塞队列里。
- 多个消费者线程:从队列里取行,解析成Data对象,判断是否存在,收集批量数据后写入数据库。
注意:要配置足够的数据库连接池大小(比如Tomcat的dbcp2配置maxTotal到20-30),避免连接不够用。
4. 数据库层面的关键优化
- 给address加唯一索引:这不仅能让
findAllAddresses更快,还可以直接用INSERT ... ON DUPLICATE KEY UPDATE或者INSERT IGNORE,彻底省去先查询再插入的步骤——让数据库帮你去重,效率更高。 - 关闭自动提交:在批量插入时,手动控制事务,比如每插入N条提交一次,减少事务开销。
- 调整MySQL参数:比如增大
innodb_buffer_pool_size(建议设为服务器内存的50%-70%)、innodb_log_file_size、max_allowed_packet等,优化写入性能。
预期效果
优化后,你的导入速度至少能提升20-50倍——按30GB计算,应该能在几小时内完成,而不是原来的240小时。
内容的提问来源于stack exchange,提问作者wolfizon contact
相关产品推荐
相关产品推荐

