问题描述:
之前有信创项目反馈了一个批量导入的性能问题,400条数据需要3分钟,5000条需要20分钟以上,系统初始需要导入的各类数据有上百万。
原因分析:
联系项目导入20~30条数据,并启用程序跟踪收集性能数据发现,有大量对字典表的SQL查询。
与功能开发同事沟通确认,该SQL是导入模板中有几个关联字段,用户录入的是编码或名称,后台需要根据编号或名称查询对应的Id值,目前是简单粗暴的循环处理。
原因倒是很清楚,如果只是为了减少对关联字段的查询次数,可以直接一次将关联数据全部加载做缓存处理,前提是关联数据的全量数据不能太大,否则容易导致OMM。
优化方案:
按列汇总所有数据并去重,建立当前关联列数据的Map<name, id>缓存,分批次去DB检索数据,并存入Map缓存:
1、取出一个批次的数据 names(n=names.size(), n<=500)
2、检查Map缓存中是否已存在
2.1、如果Map已缓存,就根据map直接标记检查结果,并从names移除该数据
2.2、如果n<300,则再次执行第1步骤,直至n=300或当前列所有数据均已被处理
3、select id, name from helpdata where name in (names);
4、将name->id作为键值对加入map
5、将names 与 nameList的差集,按 name –> null 加入map
6、重新执行第1步骤,直至当前列所有数据被处理完毕
此方案基于一个这样的事实:一次导入或处理的数据是相对有限的(一般而言,<=10w最多也不会超过50w,再多也是分成多个批次处理),而这一个批次中某列的关联数据有可能是百万乃至千万的量级。
如果按行循环处理,需要循环rowNum * columnNum次,以10w行、20列引用字段为例,需要执行200w次SQL查询请求;
如果一次将关联帮助数据全部加载至内存,则对于项目、往来等可能存在很大数据量的场景,会直接导致应用OOM;
按照本方案,理论上最坏的情况也仅执行4k次SQL查询请求(10w行、20列),而真实场景是一次处理的数据中关联列字段值重复概率非常高,实际执行的SQL请求和内存占用远低于理论的最大值。
效果验证:
产品功能按此方案优化,部署到项目后反馈良好:内存占用稳定,1k数据(2个关联列)处理响应时间从之前的3分钟提升至10秒左右。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?