从自己这两周优化代码执行效率上写一下记录,若能对有些朋友有些许帮助,深感荣幸。
1)一个优化思路是不影响业务的前提下,尽量减少和数据库的交互
以我们的预算项目为例,前期有一个需求是分类别计算预算的金额(工资、公积金、福利费等),这个计算需要查询下级近三年的历史数、计算的公式、是否计算过数据(用于判断是更新还是新增)等,计算过后将计算的结果保存并推送一下,这个是比较简单的,一个一个计算并保存就可以,也没有效率问题。
后来新增了一个需求,批量计算各个项目的预算金额,这时候我想不就是和一个和多个的问题吗,So Easy。然而坑来了,我循环的调用以前的方法分别进行计算保存,15个科目的时候没什么影响,但是到了50个科目进行计算时候,效率问题立马就出现了,接口的响应时间由300ms极速攀升至近2分钟。
这时候这个问题已经非常折磨人了,我意识到我踩坑了。然后开始想办法优化,优化的第一步是执行查看瓶颈在哪里,看看那些地方比较消耗时间。我分别添加了和查询历史数、保存计算数据、计算、查询公式的耗时总长日志,发现了问题所在。查询和保存花费时间占比达99.9%,计算的时间少到可以忽略不计。
其中,查询历史数花费时间占比达到56.5%,查询公式的时间占比13.5%,保存所占用的时间27%。那么接下来的优化方向就非常明确了。优先优化查询!!!!!然后优化保存,公式查询排在第三位。
既然方向明确了,那么就开始着手优化,看看查询为什么占比达到这么大。第一步当然是查看查询的sql有没有问题,经过Explain 查询sql后发现确实有优化的空间,然后进行了部分优化(此处不再深诉查询sql的优化了,有兴趣的可以自行去学习)。优化后测试,查询花费时间占比减少到49%,效果并不显著。
随后进行代码层面的优化,主要进行了如下的操作,首先将原来的方法进行拆分为查询数据和计算方法,让计算和查询数据进行分离,第二步将查询进行整合,这一步尤为关键,将需要5000+次查询的数据分成50次查询出来,然后使用内存缓存;将查询的科目多个组合用in一次性查询出来,然后放在Map缓存里,用的时候直接根据项目的编码进行get即可。这一步直接将查询的时间占比从49%下跌到8%,效果是非常显著的。
对于保存数据也是用了同样的方法,那就是不是一条一条保存,将所有需要保存的数据分别放入,updateList和saveList,然后进行批量的更新与插入。
保密原因不能上传代码,还请海涵。