• 记录一次查询接口优化过程


    前几天业务方反馈有一个接口查询时间,超过了1.5秒,不能忍了,让我看看,我看了下逻辑,对其中的一些逻辑进行了优化,也比较简单,这里做一个记录。

    1.第一个改造就是

    List<CallSaleInfoDto> callSaleInfoDtos = CallSaleInfoDto.fromEntity(callSaleInfoList, new CallSaleInfoDto());
    
    • 1

    这个方法本质上还是使用了
    BeanUtils.copyProperties(dto, entity);
    这个方法耗时特别长,200个数据耗时将近要1秒左右,后来改成 Lambda形式,200个时间缩短到10毫秒左右

    List<CallSaleInfoDto> callSaleInfoDtos = callSaleInfoList.stream().map(
            callSale -> {
                CallSaleInfoDto dto = new CallSaleInfoDto();
                dto.setId(callSale.getId());
                dto.setUserId(callSale.getUserId());
                dto.setName(callSale.getName());
                dto.setProperty(callSale.getProperty());
                dto.setPrivateNum(callSale.getPrivateNum());
                dto.setBindTel(callSale.getBindTel());
                dto.setWorkPhone(callSale.getWorkPhone());
                dto.setTeam(callSale.getTeam());
                dto.setLogin(callSale.getLogin());
                dto.setBusy(callSale.getBusy());
                dto.setDeleted(callSale.getDeleted());
                dto.setSupplier(callSale.getSupplier());
                dto.setAxbSupplier(callSale.getAxbSupplier());
                dto.setCreateTime(callSale.getCreateTime());
                dto.setUpdateTime(callSale.getUpdateTime());
                dto.setBusyChangeTime(callSale.getBusyChangeTime());
                dto.setRrcCno(callSale.getRrcCno());
                return dto;
            }
    ).collect(Collectors.toList());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    还有一个:

    for (int i = 0; i < callSaleInfoDtos.size(); i++) {
        List<CallSaleDetail> callSaleDetailList = callSaleService.getDetailByCCid(callSaleInfoDtos.get(i).getId());
        callSaleInfoDtos.get(i).setCallSaleDetailList(callSaleDetailList);
    }
    
    • 1
    • 2
    • 3
    • 4

    这里遍历了每一个值,然后去查询数据库,这样如果有200个数据,就会跟数据库有200次的IO交互,对数据库的压力很大,并且耗时也很大,改成了下面这种

    List<Integer> idList = callSaleInfoDtos.stream().map(s -> s.getId()).collect(Collectors.toList());
    List<CallSaleDetail> callSaleDetailList = callSaleService.getDetailByCcIds(idList);
    if (CollectionUtils.isEmpty(callSaleDetailList)) {
        return Response.ok(Collections.emptyList());
    }
    Map<Integer, List<CallSaleDetail>> callSaleDetailMap = callSaleDetailList.stream().collect(Collectors.groupingBy(CallSaleDetail::getCcId));
    for (int i = 0; i < callSaleInfoDtos.size(); i++) {
        List<CallSaleDetail> detailList = callSaleDetailMap.getOrDefault(callSaleInfoDtos.get(i).getId(), Collections.emptyList());
        callSaleInfoDtos.get(i).setCallSaleDetailList(detailList);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    改成了上面这种,首先拿到id列表,然后再数据库中使用in 查询一次数据库,将结果再使用Lambda 转换成Map,最后再根据map去匹配,在set进去最终的结果。

    这里要注意的一点是 mysql对 in 也有要求,有的时候也会不走索引,但是这里最多就几百个,并且表中的总数据也就2000左右,问题不大。

    结论:

    1、改造前这个接口平均1.5秒,改造后 平均相应300毫秒,提升了5倍

    那么问题来了,使用Lambda为啥会这么快呢?这值得研究一下:
    java8特性lambda基本原理及性能分析:https://blog.csdn.net/heima201907/article/details/104983485
    有时间看一下这篇文章,今天先写到这里

  • 相关阅读:
    springboot security使用
    什么是多态?java 中实现多态的机制是什么?
    【学习记录25】学习一些比较有用的git命令
    grpc 常用的几种通信模式
    Spring之更便捷的读取和存储对象
    1130:找第一个只出现一次的字符
    Django之DRF框架(四)“路由组件”、“认证、权限、限流”等组件的使用,及如何生成接口文档
    Leetcode刷题16. 最接近的三数之和
    pandas或者matplotlib的饼图pie
    Unity反编译:IL2CPP 打包输出的cpp文件和dll(程序集)位置、Mono打包输出的dll(程序集)位置
  • 原文地址:https://blog.csdn.net/liuying1802028915/article/details/127891593