批量导出性能优化 消除 N+1 查询与协程并发
问题
病害导出 Excel 的时候,每条病害都得查它的类型颜色、所属层位、雷达文件的里程数组……最早是”遍历病害、一条一条查库”,导出几百上千条的时候,查库次数跟着病害数线性往上涨——典型的 N+1。批量导出耗时的大头全花在查库上,反而不是绘图。
优化
分三步走:
批量预查询,干掉 N+1
把循环里那条单查,改成开头一次性批量查、构个 Map 缓起来:
val colorMap = service.batchQueryColors(defects.map { it.typeId }) |
像病害类型颜色这种”N 条病害其实只有几种类型”的数据,批量查一次,查询次数从 N 降到 1。
按雷达文件分组,共享渲染上下文
原来每条病害导出截图都要重新打开雷达文件、重算里程数组。改成按雷达文件分组,同一个文件的病害共享一次”开文件 + 算里程数组”的上下文,省掉一堆重复 IO。
协程并发各文件
分完组,各雷达文件的导出互相不依赖,用 async 并行跑,ConcurrentHashMap 收集结果:
coroutineScope { |
效果
大批量导出(几百条病害)的耗时从”肉眼等待”降到秒级。瓶颈从查库、重复 IO 挪到了真正绘图那一步,这才算优化到点子上。
我的经验是,性能优化先揪 N+1 和重复 IO 这种”明摆着的浪费”,再谈并发。批量预查 + 分组共享上下文 + 协程并行,基本就是这类导出场景的老三样。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 CYK's Blog!
评论
