批量导出性能优化 消除 N+1 查询与协程并发
问题
病害导出 Excel 时,每个病害要查它的类型颜色、所属层位、雷达文件里程数组……最开始是“遍历病害,逐条查库”,导出几百上千条病害时,数据库查询次数跟病害数线性涨——典型的 N+1。批量导出耗时主要耗在查库上,而不是绘图。
优化
三步走:
1. 批量预查询,干掉 N+1
把循环内的单条查询改成开始时一次性批量查,构造 Map 缓存:
val colorMap = service.batchQueryColors(defects.map { it.typeId }) |
病害类型颜色这种“N 个病害只有几种类型”的数据,批量查一次从 N 次查询降为 1 次。
2. 按雷达文件分组,共享渲染上下文
原来每个病害导出截图都重新打开雷达文件、重算里程数组。改成按雷达文件分组,同一文件的病害共享一次“打开文件 + 计算里程数组”的上下文,避免重复 IO。
3. 协程并发各文件
分组后,各雷达文件的导出互相独立,用 async 并行,ConcurrentHashMap 收集结果:
coroutineScope { |
效果
大批量导出(几百条病害)耗时从“明显等待”降到秒级。瓶颈从查库 / 重复 IO 转移到真正的绘图上,优化才算做到点子上。
小结
性能优化先抓 N+1 和重复 IO 这类“明显浪费”,再做并发。批量预查 + 分组共享上下文 + 协程并行,基本是这类导出场景的通用三板斧。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 CYK's Blog!
评论
