关于在代码查询的数据库的问题

来源:9-7 你写的 SQL 可能很慢,怎样做优化呢?

SuccessorSocialism

2020-09-28

需求: 就是在需要展示当前公司旗下的公司折扣值 和公司员工对应的折扣值

// 1. 先查当前公司的折扣值~~~
EntBaseDiscount entBaseDiscount = CompletableFuture.supplyAsync(() -> entBaseDiscountService.
        findEntByTypeAndEntId(entId)).get();

// 2.当前公司的所有的部门
// -- 当员工加入多个部门时 则展示最后一个加入的部门名
Map<Integer, ApiUserDeptMapping> deptMappingMap = CompletableFuture.supplyAsync(() -> userDeptMappingService.
        findByEntIdAndStatus(entId)).get().stream().collect(Collectors.toMap(BaseApiUserDeptMapping::
        getMappingId, dept -> dept, (d1, d2) -> d2));

Map<Integer, EntDept> deptMap = CompletableFuture.supplyAsync(() -> deptService.findByEntIdAndStatus(entId))
        .get().stream().collect(Collectors.toMap(BaseEntDept::getId, dept -> dept));
// todo 过滤出以加入部门的 已加入部门则显示部门名 未加入则显示企业名
// 3..求差集 即在折扣设置表中存在的员工 即按折扣表中的展示 若在折扣表中不存在的即按公司的统一折扣展示
List<EntBaseDiscount> staffsBaseDiscount = entBaseDiscountService.findStaffsByTypeAndEntId(entId);

List<Integer> staffIds = staffsBaseDiscount.stream().sorted(Comparator.comparing(BaseEntBaseDiscount::getStaffId))
        .map(BaseEntBaseDiscount::getStaffId).collect(Collectors.toList());

List<ApiUserEntMapping> userEntMappings = userEntMappingService.findByEntId(entId);
// 没有在折扣表进行设置的员工 所以折扣值统一展示为公司的折扣值
Map<Integer, ApiUserEntMapping> mappingMap = userEntMappings.stream().filter(mapping -> !staffIds.contains(mapping
        .getUserInfoId())).collect(Collectors.toMap(BaseApiUserEntMapping::getUserInfoId, mapping -> mapping));

Map<Integer, ApiUserEntMapping> entMappingMap = userEntMappings.stream().collect(Collectors.toMap
        (BaseApiUserEntMapping::getUserInfoId, mapping -> mapping));

List<Integer> userInfoIds = userEntMappings.stream().sorted(Comparator.comparing(BaseApiUserEntMapping::getUserInfoId)).
        map(BaseApiUserEntMapping::getUserInfoId).collect(Collectors.toList());

List<Integer> userIds = userEntMappings.stream().sorted(Comparator.comparing(BaseApiUserEntMapping::getUserId)).
        map(BaseApiUserEntMapping::getUserId).collect(Collectors.toList());

Map<Integer, ApiUserInfo> userInfoMap = apiUserInfoService.findByBetweenId(userInfoIds).stream().collect(Collectors
        .toMap(BaseApiUserInfo::getId, userinfo -> userinfo));

Map<Integer, ApiUser> userMap = apiUserService.findByBetweenId(userIds).stream().collect(Collectors.toMap
        (BaseApiUser::getId, user -> user));

List<DiscountVo> discountVos = new ArrayList<>();
// 没有单独进行折扣设置的员工列表
System.out.println(mappingMap.size());
mappingMap.forEach((k, v) -> {
    ApiUserInfo userInfo = userInfoMap.get(k);
    EntDept dept = deptMap.get(deptMappingMap.get(v.getId()).getDeptId());
    ApiUser user = userMap.get(v.getUserId());
    discountVos.add(new DiscountVo(k, userInfo.getAvatar(), userInfo.getName(), userInfo.getPosition(),
            dept.getName(), user.getMobile(), entBaseDiscount.getDiscountRate()));
});

// 单独进行折扣设置的员工列表
Map<Integer, EntBaseDiscount> discountMap = staffsBaseDiscount.stream().collect(Collectors.toMap
        (BaseEntBaseDiscount::getStaffId, staff -> staff));


discountMap.forEach((k, v) -> {
    ApiUserEntMapping entMapping = entMappingMap.get(k);
    ApiUserInfo userInfo = userInfoMap.get(k);
    EntDept dept = deptMap.get(deptMappingMap.get(entMapping.getId()).getDeptId());
    ApiUser user = userMap.get(entMapping.getUserId());
    discountVos.add(new DiscountVo(k, userInfo.getAvatar(), userInfo.getName(), userInfo.getPosition(),
            dept.getName(), user.getMobile(), v.getDiscountRate()));
});

我是先查询所有的数据 然后再去单独汇总  然后表哥看了这部分说很容易造成"性能瓶颈" ,还不如foreach里面一条一条去查,因为有些是有id cache的,但是还有几部分我是不会根据id 去查的  ,所以我都先查一个List 然后去过滤出我需要的数据 最后在进行拼装... 
我的问题就是 我这样子的写法 很容易出现性能瓶颈吗?

后续服务器的配置大概是  4核8G的样子 然后目前还处于开发阶段.... 没有什么数据量

写回答

2回答

张勤一

2020-09-28

琨陈你好:

    首先,我们先从实现上来说,你的这种做法是没问题的,而且也是我个人推荐的做法。原因其实是很明确的,我们思考:

    即使是可能对于部分数据来说存在缓存,那么,一定会命中吗?命中的占比有多少?如果缓存失效,是不是 foreach 中的每一个查询都会去扫库呢?这显然会导致性能急剧下降。

    但是,虽然我这里给出了我建议的方案,但是,我仍然给你提出几点关于接口实现的说明,你需要认真的思考以下的几点,不过,灵活运用,不需要写每一个接口都去这样想来想去,否则,可能就是投鼠忌器了:

    (1)这个接口的访问频率是怎样的?如果不高,任你怎么玩

    (2)这个接口中处理的数据量有多大?如果不多,任你怎么玩,毕竟现代 CPU 的性能如此强悍,业务又会有多复杂的逻辑呢?

    (3)这个接口需要考虑安全问题吗?如果需要,那么,以最少的信息返回,不要多返回任何不必要的数据

    (4)这个接口需要做登录、权限相关的校验吗?如果有很多类似这样的判断,是不是可以考虑写个切面统一化处理呢?

    (5)这个接口需要考虑限流逻辑吗?如果有很多类似这样的判断,是不是可以考虑写个切面统一化处理呢?


    我是勤一,致力于将这门课程的问答区打造为 Java 知识体系知识库,Java 知识体系 BBS!共同建造、维护这门课程,我需要每一个你!


1
1
SuccessorSocialism
1024 感谢分享
2020-10-05
共1条回复

SuccessorSocialism

提问者

2020-09-28

代码格式乱了 ----代码贴图 

//img.mukewang.com/szimg/5f7186890930694812631037.jpg


//img.mukewang.com/szimg/5f71868909217af110850652.jpg


1
0

Java实操避坑指南 SpringBoot/MySQL/Redis错误详解

掌握业务开发中各种类型的坑,,Java web开发领域通用

466 学习 · 204 问题

查看课程