java-性能优化篇

java-性能优化篇

因为一次公司倒闭,感悟到人生不容易,选择以物联网做副业,从事物联网卡代理,希望认识更多好朋友,合作共赢.

(当你身上有了担子,你就会发现,收入来源太单一,会使你没有安全感!)

公司项目已经完成阶段性上线,目前正在对残留的一些性能问题进行优化,今天针对优化过程中的一系列流程进行整理,希望能帮助到各位。我们单纯的先从软件层面出发(硬件的说实话,不是很good at)

第一步:分析性能问题

首先,可以依据类似听云这类全链路日志,可以看到整个接口的调用链路以及响应时间。每个sql语句的耗时以及后续api的调用时长。
请添加图片描述

第二步:分块优化

大多数情况下,性能问题是由于一些慢sql导致的,那么接下来,面试时问到的一些关于sql优化的方案就可以派上用场了。

SQL层面
  1. 从建表出发

    1.1 CHAR是可变长字符串,VARCHAR是固定大小,字符类型尽量根据实际预存值大小设置,否则会浪费空间;

    1.2 尽量避免出现null值,给缺省值(默认值);

    1.3 能用int类型的不要用varchar或者char类型,否则mysql比较相等时,会默认每个字符依次匹配;

  2. 从索引的角度出发
    2.1 是否添加必要索引 ?
    所谓必要列的索引,指的是不会频繁更新的,与其他表关联的,小的字段

    2.2 ** 执行计划中查看是否命中索引?**
    有时存在sql优化器自动选取较优索引,如果不是实际最优,我们可以用**use index(index_name)**指定使用某个索引;

    2.3 如果存在复合索引,那么请注意where后面的过滤条件的先后顺序是否遵循索引的最左原则;

  3. 从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(理论上)

    3.5 sql尽量避免回表。在innodb聚集索引的情况下,主键索引的叶子结点存储实际数据,非主键索引存储索引字段数据以及主键索引位置;如果sql查询的字段超出非主键索引的存储字段,则需要根据非主键索引找到主键索引,再去查对应的额外数据,这个过程就叫做回表。具体参考mysql索引

    例如:user表有id,age,name,address字段,id为主键索引,根据(age,name)创建非主键索引;
    select age,name,address from user where age = ? and name = ? ,会触发回表,先找到索引数据,再找到索引对应的主键索引位置,再找到主键索引拿到address数据;

代码层面
  1. 如果存在分页查询,分页查询时自定义查询总数语句,去除多余表关联;
    例如:
    传来岗位集合和考试id,查询每个岗位下的考试试题情况,可以直接查询考试下的题目数量*岗位集合size=总数,无需在关联 多余的表,只需要关心最细粒度的分页数据;

  2. 如果需要查询没有依赖关系的多个数据,考虑多线程异步查询,耗时取多个任务中的最大值(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();
     }
    
    
        /**
         * 查询正确答案
         * @param countDownLatch
         */
        @Async
        public void getQuesCorrectAnswer(Map<String, List<OteUserAnswerDetail>> answerDetailMap,
                String orgId,List<String> uqIds,CountDownLatch countDownLatch,) {
            try {
               // --------
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                countDownLatch.countDown(); // finally一定要执行countdown(),否则会阻塞
            }
        }
    
  3. 针对sql较多的任务,并行流很ok,针对计算任务较多的,线程数不宜过多,会造成额外的cpu切换开销;

  4. 并行流操作list,map之类的,切记一定要用CopyOnArrayList、ConcurrentHashMap之类的线程安全的集合,否则会空指针

  5. 后续补充。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值