刚入职,安排了一个两年多没人碰的项目,用户说有一个功能执行的非常慢,大概要跑三个多小时才能完事,于是让我调一下。
看了下代码,呆了。。。全屏的for循环套for循环
for(T t : TList){
...
此处省略一些数据库查询
for(M m : MList){
此处省略一些数据库查询
...
}
}
SQL基本就是
select * from 表 where a=#{a} and b=#{b}...
基本代码上没有什么难度,我试着点了一下那个功能,就没管它了,过了15分钟,页面还在转圈圈,看了眼后台,疯狂的刷SQL日志,我只能强行中断了...每个SQL执行80-100ms不等,但是禁不住多,据客户讲,执行了3个多小时才完事
下面就记录一下优化流程,以备后续再有相关的粑粑山等着
以下有些并不是优化,算是规范吧
1.清理掉所有注释掉的代码,空行,涉及到的private方法的参数都加上注释,这一步算是拯救强迫症
2.清理if else,代码有一个12连的ifelse,改成switch,字符串判空,集合判空用专门的工具类
3.优化批量插入,把每次循环里的save(entity)删掉,entity存入list中,批量insert,每次1000条
4.优化批量更新,把每次循环里的update(entity)删掉,entity存入list中,批量update,由于项目没有引入mybatisPlus,所以使用mybatis进行批量更新,此处选择了一种不是特别高效的更新方式,但是也比较可以
<update id="updateBatch" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update 表
<set>
name=${item.name}
</set>
where id = ${item.id}
</foreach>
</update>
这种操作jdbc配置文件需要增加
allowMultiQueries=true
5.优化批量查询,主要处理for循环嵌套导致的效率降低,由于需求中是每次循环时拼接不同的参数进行单表的查询,修改为查出全表(不带条件),然后利用filter进行条件过滤
list.stream().filter(e -> e.getName().equals("参数") &&
e.getAge() == 20).findAny();
findAny或findFirst会返回Optional<T>,可以利用isPresent()判断是否返回null,不为null可以直接get()获取T