闲得无聊,本来是很简单的增删改查。但是,由于表设计的草蛋(所以,别问我为什么不用表连接o(╥﹏╥)o接盘的痛,又不能影响公司正在运行中的功能),以及我代码的草蛋。使得其中有一个需求——“导出excel”表,预计会由于出现几千次访问数据库而影响性能。
页面交给前端写,划水中,试试改善下性能。
考虑到:
java内存运行,速度影响不大。
mysql允许in(xx,yy)的功能,性能影响不大。
例如:
SELECT * FROM `oa_meal_offer` where (job_num, DATE_FORMAT(order_date,'%Y-%m-%d')) in (('CBR023','2020-03-30'));
性能瓶颈:java多次访问数据库Mysql
百度到:
springMVC+mybatis,如何实现批量多条件的查询?mybatis 中 foreach 的性能问题及调优
教会了我这么干:
优化前的垃圾代码
String type=(String)params.get("type");
PageUtils page=null;
//type为空时,认为和"3"一个场景
if(!StringUtils.isNotBlank(type)||type.equals("3")){
//如果选的是全部,需要单独处理。又要分组(sql表关联自己,做成中、晚、早三张表关联),又要分页
page=applyMealRecordService.queryAllApplyMealRecordListPage(params);
}else {
page = applyMealRecordService.queryApplyMealRecordListPage(params);
}
//得到realOrderTimeStr //估计导excel表时会影响性能
List<ApplyMealRecordEntity> list = (List<ApplyMealRecordEntity>) page.getList();
for(ApplyMealRecordEntity a:list){
String strDate=DateUtils.format(a.getInsertTime(),DateUtils.DATE_PATTERN);
String jobNum=a.getJobNum();
Date dateTime=applyMealRecordService.selectRealOrderTimeByJobNumAndDate(jobNum,strDate);
a.setRealOrderTimeStr(DateUtils.format(dateTime,DateUtils.DATE_TIME_PATTERN));
}
mybatis
<select id="selectRealOrderTimeByJobNumAndDate" parameterType="string" resultType="java.util.Date">
select insert_time from oa_meal_offer where job_num=#{jobNum} and DATE_FORMAT(order_date,'%Y-%m-%d') =#{strDate} limit 1
</select>
优化后:
java:
/**
*Controller层
*/
/**
* 分页查询
* web查询 报餐记录
*/
@GetMapping("/list")
@RequiresPermissions("oa:applymeal:list")
public R getApplyMealRecordList(@RequestParam Map<String, Object> params){
String type=(String)params.get("type");
PageUtils page=null;
//type为空时,认为和"3"一个场景
if(!StringUtils.isNotBlank(type)||type.equals("3")){
//如果选的是全部,需要单独处理。又要分组(sql表关联自己,做成中、晚、早三张表关联),又要分页
page=applyMealRecordService.queryAllApplyMealRecordListPage(params);
}else {
page = applyMealRecordService.queryApplyMealRecordListPage(params);
}
//得到realOrderTimeStr
List<ApplyMealRecordEntity> list = (List<ApplyMealRecordEntity>) page.getList();
//写法一
//存在多次访问数据库。估计导excel表时,数据太多,性能8行
/*
for(ApplyMealRecordEntity a:list){
String strDate=DateUtils.format(a.getInsertTime(),DateUtils.DATE_PATTERN);
String jobNum=a.getJobNum();
Date dateTime=applyMealRecordService.selectRealOrderTimeByJobNumAndDate(jobNum,strDate);
a.setRealOrderTimeStr(DateUtils.format(dateTime,DateUtils.DATE_TIME_PATTERN));
}*/
//优化性能。写法二
//获取工号、时间的集合 (applyMeal对象用applyMealRecord对象存其实也行吧,我只取两个属性就够了)
List<ApplyMealEntity> oaMealOfferList= applyMealRecordService.selectRealOrderTimeFaEr(list);
//遍历,根据工号匹配
for(ApplyMealRecordEntity a:list){
for(ApplyMealEntity b:oaMealOfferList){
if(b.getJobNum().equals(a.getJobNum())){
// 得到realOrderTimeStr。格式化时间,赋值给a.setRealOrderTimeStr()
a.setRealOrderTimeStr(DateUtils.format(b.getInsertTime(),DateUtils.DATE_TIME_PATTERN));
}
}
}
//page.setList(list); //多余,集合、对象是引用数据类型。
return R.ok().put("page", page);
}
/**
*Service层
*ServiceImpl
*/
@Override
public List<ApplyMealEntity> selectRealOrderTimeFaEr(List<ApplyMealRecordEntity> list) {
//有两种考虑,目前认为:在java拼接,然后在mybatis用$预加载,性能会更好
// 参数串 ('CBR023','2020-03-30'),('CBR024','2020-03-30'),('CBR025','2020-03-30')
List<String> sbs=new ArrayList<String>();
for(ApplyMealRecordEntity a:list){
String jobNum=a.getJobNum();
String strDate= DateUtils.format(a.getInsertTime(),DateUtils.DATE_PATTERN);
StringBuffer sb=new StringBuffer();
sb.append("(").append("'").append(jobNum).append("'").append(",").append("'").append(strDate).append("'").append(")");
sbs.add(sb.toString());
}
String paramsStrs1=String.join(",", sbs);
String paramsStrs="("+paramsStrs1+")";
return baseMapper.selectRealOrderTimeFaEr(paramsStrs);
}
//dao
/**
* 法二:
*根据工号和时间,查询真实的下单时间
* 性能优化
*
* xml用${}时需要加@Param()
*/
List<ApplyMealEntity> selectRealOrderTimeFaEr(@Param("paramsStrs") String paramsStrs);
mybatis
<select id="selectRealOrderTimeFaEr" parameterType="string" resultType="com.cowain.base.modules.oa.entity.ApplyMealEntity">
SELECT * FROM `oa_meal_offer` where
(job_num, DATE_FORMAT(order_date,'%Y-%m-%d'))
in
${paramsStrs}
</select>
// 其实此ApplyMealEntity对象里我只需 job_num,insert_time这两个数据/属性就够了
总结:
此次性能优化本质:用java内存运行的性能(内存里操作,反正很快的)换连接数据库交互(内存和硬盘,很慢)的蛋疼
20200406:我擦,我发现逼逼这么多,把offer表做主表,去left join record表就行了o(╥﹏╥)o妈的,都怪测试库数据残缺,搞得我看效果很蛋疼
补充:
20200414今天加了一个参数,又加出蛋疼来了(又自己写bug折腾自己喽):
1. ${}别写成$ {} 【navicat"美化sql"给我格式化成这个鸟样】,不识别的-_-||
2.注意,只能用${} 用#{}会报错:版本不支持in,跟字符串有关,好像会多'' (用#得在xml里搞循环,性能差一点)
AND (s.hr_id) IN ${ paramsStrs }
3. month是关键字,记得上一层@Param("cmonth") ,这里就可以是${ cmonth }了,而不会sql关键字冒橘黄了
其他照旧,比如parameterType="string",@Param("cmonth")String month