因为一次公司倒闭,感悟到人生不容易,选择以物联网做副业,从事物联网卡代理,希望认识更多好朋友,合作共赢.
(当你身上有了担子,你就会发现,收入来源太单一,会使你没有安全感!)
公司项目已经完成阶段性上线,目前正在对残留的一些性能问题进行优化,今天针对优化过程中的一系列流程进行整理,希望能帮助到各位。我们单纯的先从软件层面出发(硬件的说实话,不是很good at)
第一步:分析性能问题首先,可以依据类似听云这类全链路日志,可以看到整个接口的调用链路以及响应时间。每个sql语句的耗时以及后续api的调用时长。
大多数情况下,性能问题是由于一些慢sql导致的,那么接下来,面试时问到的一些关于sql优化的方案就可以派上用场了。
SQL层面从建表出发
1.1 CHAR是可变长字符串,VARCHAR是固定大小,字符类型尽量根据实际预存值大小设置,否则会浪费空间;
1.2 尽量避免出现null值,给缺省值(默认值);
1.3 能用int类型的不要用varchar或者char类型,否则mysql比较相等时,会默认每个字符依次匹配;
从索引的角度出发
2.1 是否添加必要索引 ?
所谓必要列的索引,指的是不会频繁更新的,与其他表关联的,小的字段;
2.2 ** 执行计划中查看是否命中索引?**
有时存在sql优化器自动选取较优索引,如果不是实际最有,我们可以用**use index(index_name)**指定使用某个索引;
2.3 如果存在符合索引,那么请注意where后面的过滤条件的先后顺序是否遵循索引的最左原则;
从sql语句出发
3.1 避免大数据量in查询(一般超过200,索引就显得力不从心了);
3.2 能用关联查询的尽量不用子查询(子查询会生成临时表,表的创建和销毁有性能开销);
3.3 如果存在类似union查询两端都需要基于某张表做各自的统计查询,这个时候**CTE(with as)**语句就很nice;
with temp_table as( select id, name ,age from user where schoole_id ="" ) select * from temp_table; 通过with as创建公用表表达式,后续的sql都可以直接用已经生成(过滤后)的公用表做操作。
3.4 如果join两边的表数据量特别大,并且过滤条件能有效的过滤掉很大一部分数据,可以尝试先子查询过滤在join(理论上)
如果存在分页查询,分页查询时自定义查询总数语句,去除多余表关联;
例如:
传来岗位集合和考试id,查询每个岗位下的考试试题情况,可以直接查询考试下的题目数量*岗位集合size=总数,无需在关联 多余的表,只需要关心最细粒度的分页数据;
如果需要查询没有依赖关系的多个数据,考虑多线程异步查询,耗时取多个任务中的最大值(countdownlatch);、
CountDownLatch countDownLatch = new CountDownLatch(4); // 开启4个线程异步执行查询
try{
// 第一次考試信息
erver.getFirstInfo(examInfoDOMap,orgId,uemIdsList,countDownLatch);
// 最高分信息
erver.getTopInfo(topUserExamInfoDOHashMap,orgId,uemIdsList,countDownLatch);
// 平均分&考试次数
erver.getOtherInfo(eaCntAndAvgScoreMap,orgId,uemIdsList,countDownLatch);
// 正确答案
erver.getQuesCorrectAnswer(answerDetailMap,orgId,uemIdsList,countDownLatch);
countDownLatch.await(); // 主线程等待4个线程执行结束才继续执行
}catch (Exception e){
e.printStackTrace();
}
@Async
public void getQuesCorrectAnswer(Map> answerDetailMap,
String orgId,List uqIds,CountDownLatch countDownLatch,) {
try {
// --------
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
countDownLatch.countDown(); // finally一定要执行countdown(),否则会阻塞
}
}
针对sql较多的任务,并行流很ok,针对计算任务较多的,线程数不宜过多,会造成额外的cpu切换开销;
并行流操作list,map之类的,切记一定要用CopyOnArrayList、ConcurrentHashMap之类的线程安全的集合,否则会空指针;
后续补充。。。



