前言:本文章记录了技术小白遇到问题的解决步骤与所思所想,参考了不少大佬的分享,如有侵权请联系我删除。
一. 背景引入与SELECT语句优化(第一次优化)
这两天接着前几天的工作,我在写完一个不同取整策略影响等级分段的接口之后,现在要根据不同科目以及其划分的等级分数段、将数据库表中原始成绩将其做转换并得到赋分成绩,然后将其保存下来。
怎么设计这部分数据库的逻辑?原始成绩肯定要查,一条select语句是必然要存在的,其次根据我写的赋分转换的接口,我最开始的想法是:根据原始成绩得到赋分成绩之后,将所有成绩都是原始成绩的数据一起把他的赋分成绩给更新了(因为我们不必关心考生是谁、考生ID等信息,我们就想把这个赋分后的成绩给记录下来,这里并没有进一步深入的想,也为后面埋下了祸根......),那么另一条update语句也必不可少。
public R updateGradeScore(OriScoreBody oriScoreBody) {
Map<String, Integer> boundaryScoreMap = oriScoreBody.getBoundaryScoreMap();
String subject = oriScoreBody.getSubject();
List<Score> scoreList = scoreMapper.selectScoreListBySubject(subject);
for(Score score : scoreList) {
Integer oriScore = score.getCourseScore();
Integer calculatedScore = convertToGradeScore(subject,oriScore,boundaryScoreMap);
scoreMapper.updateGradeScore(subject,oriScore,calculatedScore);
}
return R.ok("已将原始成绩计算为赋分成绩并插入成绩对照表");
}
Mapper:
@Select("SELECT * FROM score WHERE course_code = #{courseCode} " )
@Update("UPDATE score SET calculated_score = #{calculatedScore} " +
"WHERE course_score = #{courseScore} AND course_code = #{subject}")
写完之后乍一看没啥问题,感觉信心满满,用Postman测试了一下,看着一直转圈的postman我陷入了沉思,估计要出事儿,去数据库一看才想起来, 表里选1这门课的记录有六十多万条,很合理,因为一百三十万考生每人选两门,那么一门差不多就是六十多万个人选。这就意味着转换完一个分数之后,我要给所有这个分数的行进行一次update更新字段,耗时会非常大。因此考虑优化,一共两条SQL语句,一个一个来。
Select语句一般是比较快的,我写了条测试了一下,大概7s左右即可查询到六十五万条数据的所有信息,毕竟有索引,还是比较给力的,但是我敏锐的发现这里有一个问题,因为我Mapper查询到的数据返回的是List<Score>类型,显然在for循环遍历的时候,要遍历六十多万次,每一次都去执行赋分成绩的转换以及UPDATE语句写库,时长直接爆炸。