树形结构数据数据查询优化过程

news2024/12/25 23:43:46

树形结构数据统计查询优化过程

初始方案:

组织树数据结构如下:
在这里插入图片描述

数据请求参数:
在这里插入图片描述

原技术方案:

 public List<Map<String, List<Long>>> getSelectParam(List<DepartmentQueryDTO> departmentList, String reportName, String dataLevel) {
        if (CollectionUtils.isEmpty(departmentList)) {
            return null;
        }
        //根据report获取mapping
        //从树上查询出需要的所有维度值
        List<Long> orgDimensionIdList = departmentList.stream().map(t -> t.getDimensionMap().keySet()).flatMap(Set::stream).distinct().collect(Collectors.toList());

        //List<Long> orgDimensionIdList = departmentList.stream().map(DepartmentQueryDTO::getDimensionId).distinct().collect(Collectors.toList());
        List<Map<String, List<Long>>> paramList = new ArrayList<>();
        //没有维度值,有组织机构入参,那就是返回没有数据
        if (CollectionUtils.isEmpty(orgDimensionIdList)) {
            Map<String, List<Long>> paramMap = new HashMap<>();
            paramMap.put("1", Lists.newArrayList(0L));
            paramList.add(paramMap);
            return paramList;
        }
        Map<Long, DimensionMapping> dimensionMappingMap = dimensionMappingService.findByReportAndDataLevelGroupByDimensionId(reportName, dataLevel, orgDimensionIdList);
        Assert.notNull(dimensionMappingMap, "请在DIMENSION_MAPPING表中配置组织树相关的参数之后,再尝试!");
        Map<Long, List<Long>> childrenIdMap = departmentList.stream().filter(data -> data.getPid() != null).collect(Collectors.groupingBy(DepartmentQueryDTO::getPid, Collectors.mapping(DepartmentQueryDTO::getId, Collectors.toList())));
        boolean outOfDimensionFlag = Boolean.FALSE;
        for (DepartmentQueryDTO department : departmentList) {
            //记录维度列值及对应ID值
            Map<String, Long> dimensionColumnIdMap = new HashMap<>();
            List<Long> childrenId = childrenIdMap.get(department.getId());
            Map<String, List<Long>> paramMap = new HashMap<>();
            if (CollectionUtils.isEmpty(childrenId)) {
                //子节点
                for (Map.Entry<Long, Long> entry : department.getDimensionMap().entrySet()) {
                    DimensionMapping dimensionMapping = dimensionMappingMap.get(entry.getKey());
                    if (Objects.isNull(dimensionMapping)) {
                        outOfDimensionFlag = true;
                        paramMap.clear();
                        break;
                    }
                    if (department.isSelected() && department.isPermission()) {
                        paramMap.put(dimensionMapping.getColumnName(), Lists.newArrayList(entry.getValue()));
                    }
                    dimensionColumnIdMap.put(dimensionMapping.getColumnName(), entry.getValue());
                }
            } else {
                //父节点
                Map<Long, Long> treeDimensionMap = department.getDimensionMap();
                Set<Long> allDimensionIdList = new HashSet<>(dimensionMappingMap.keySet());
                allDimensionIdList.addAll(treeDimensionMap.keySet());
                for (Long dimensionId : allDimensionIdList) {
                    DimensionMapping dimensionMapping = dimensionMappingMap.get(dimensionId);
                    Long dimensionValueId = treeDimensionMap.get(dimensionId);
                    List<Long> valueList = new ArrayList<>();
                    if (Objects.isNull(dimensionMapping)) {
                        outOfDimensionFlag = true;
                        paramMap.clear();
                        break;
                    }
                    if (dimensionValueId != null) {
                        dimensionColumnIdMap.put(dimensionMapping.getColumnName(), dimensionValueId);
                        valueList.add(dimensionValueId);
                    }
                    if (department.isSelected() && department.isPermission()) {
                        paramMap.put(dimensionMapping.getColumnName(), valueList);
                    }
                }
            }
            if (!paramMap.isEmpty()) {
                paramList.add(paramMap);
            }
            department.setDimensionValueMap(dimensionColumnIdMap);
        }
        //当没有查询条件并且有存在树上的维度多余配置的维度,增加一条不成立的where条件
        if (CollectionUtils.isEmpty(paramList) && outOfDimensionFlag) {
            Map<String, List<Long>> paramMap = new HashMap<>();
            paramMap.put("1", Lists.newArrayList(0L));
            paramList.add(paramMap);
        }
        return paramList;
    }

在代码中封装到departmentList中然后在mapper xml中进行遍历拼接

@ApiModelProperty(value = "department树转换后的查询参数", hidden = true)
private List<Map<String, List<Long>>> departmentList = new ArrayList<>();
<sql id="departmentBaseSql">
        <if test="departmentList != null and departmentList.size() > 0">
            AND
            <foreach collection="departmentList" item="item" separator=" OR " open="(" close=")">
                <foreach collection="item.entrySet()" item="values" index="key" separator=" AND " open="(" close=")">
                    <choose>
                        <when test="values.size() == 0">
                            `${key}` IS NULL
                        </when>
                        <when test='key == "1"'>
                            ${key} =
                            <foreach collection="values" item="value">
                                #{value}
                            </foreach>
                        </when>
                        <when test="values.size() == 1">
                            `${key}` =
                            <foreach collection="values" item="value">
                                #{value}
                            </foreach>
                        </when>
                        <otherwise>
                            `${key}` IN
                            <foreach collection="values" item="value" open="(" close=")" separator=",">
                                #{value}
                            </foreach>
                        </otherwise>
                    </choose>
                </foreach>
            </foreach>
        </if>
    </sql>
<include refid="com.pwc.sdc.OPA.mapping.CommonMapper.departmentBaseSql"/>

查看拼接的sql:
在这里插入图片描述

我们会发现有很多条件是重复的,当数据量很大的时候就非常的影响查询的性能;因为接下来的优化就是减少这些不必要的开销

优化方案:

代码中进行递归调用拼接:

public String getMySelectParam(List<DepartmentQueryDTO> departmentList, String reportName, String dataLevel) {
        if (CollectionUtils.isEmpty(departmentList)) {
            return null;
        }
        //根据report获取mapping
        //从树上查询出需要的所有维度值
        List<Long> orgDimensionIdList = departmentList.stream().map(t -> t.getDimensionMap().keySet()).flatMap(Set::stream).distinct().collect(Collectors.toList());

        //List<Long> orgDimensionIdList = departmentList.stream().map(DepartmentQueryDTO::getDimensionId).distinct().collect(Collectors.toList());
        //没有维度值,有组织机构入参,那就是返回没有数据
        if (CollectionUtils.isEmpty(orgDimensionIdList)) {
            return null;
        }
        Map<Long, DimensionMapping> dimensionMappingMap = dimensionMappingService.findByReportAndDataLevelGroupByDimensionId(reportName, dataLevel, orgDimensionIdList);
        Assert.notNull(dimensionMappingMap, "请在DIMENSION_MAPPING表中配置组织树相关的参数之后,再尝试!");
        Map<Long, List<DepartmentQueryDTO>> childrenIdMap = departmentList.stream().filter(data -> data.getPid() != null).collect(Collectors.groupingBy(DepartmentQueryDTO::getPid));
        StringBuilder stringBuilder=new StringBuilder();
        boolean isFirst=true;
        for(int i=0;i<departmentList.size();i++){
            DepartmentQueryDTO department=departmentList.get(i);
            if(Objects.nonNull(department) && Objects.isNull(department.getPid())){
                if(isFirst){
                    stringBuilder.append(" (`");
                    isFirst=false;
                }else {
                    stringBuilder.append(" OR (`");
                }
                DimensionMapping dimensionMapping = dimensionMappingMap.get(department.getDimensionId());
                stringBuilder.append(dimensionMapping.getColumnName());
                stringBuilder.append("` = ");
                stringBuilder.append(department.getDimensionValueId());
                department.getDimensionIdSet().add(department.getDimensionId());
                handleSelectParam(childrenIdMap,department,dimensionMappingMap,stringBuilder,orgDimensionIdList);
                stringBuilder.append(")");
            }
        }
//        log.info(stringBuilder.toString());
        return stringBuilder.toString();
    }

public void handleSelectParam(Map<Long, List<DepartmentQueryDTO>> childrenIdMap,DepartmentQueryDTO parentDepartment,Map<Long, DimensionMapping> dimensionMappingMap,StringBuilder stringBuilder,List<Long> orgDimensionIdList) {
        List<DepartmentQueryDTO> childrenId = childrenIdMap.get(parentDepartment.getId());
        if (!CollectionUtils.isEmpty(childrenId)) {
            stringBuilder.append(" AND (");
            for(int i=0;i<childrenId.size();i++){
                DepartmentQueryDTO department=childrenId.get(i);
                department.getDimensionIdSet().addAll(parentDepartment.getDimensionIdSet());
                department.getDimensionIdSet().add(department.getDimensionId());
                if(i==0){
                    stringBuilder.append(" (`");
                }else {
                    stringBuilder.append(" OR (`");
                }
                DimensionMapping dimensionMapping = dimensionMappingMap.get(department.getDimensionId());
                stringBuilder.append(dimensionMapping.getColumnName());
                stringBuilder.append("` = ");
                stringBuilder.append(department.getDimensionValueId());
                handleSelectParam(childrenIdMap,department,dimensionMappingMap,stringBuilder,orgDimensionIdList);
                stringBuilder.append(") ");
            }
            if(parentDepartment.isSelected() && parentDepartment.isPermission() && !parentDepartment.isLeafNode() && !orgDimensionIdList.isEmpty()){
                boolean flag=true;
                for (int k=0;k<orgDimensionIdList.size();k++) {
                    if(!parentDepartment.getDimensionIdSet().contains(orgDimensionIdList.get(k))){
                        if(flag){
                            flag=false;
                            stringBuilder.append(" OR (`");
                        }else {
                            stringBuilder.append(" AND `");
                        }
                        DimensionMapping dimensionMapping2 = dimensionMappingMap.get(orgDimensionIdList.get(k));
                        stringBuilder.append(dimensionMapping2.getColumnName());
                        stringBuilder.append("` IS NULL ");
                    }
                }
                if(!flag){
                    stringBuilder.append(")");
                }
            }
            stringBuilder.append(") ");
        }

    }

mapper xml中使用

 <choose>
     <when test="condition.condi != null and condition.condi != ''">
     AND (${condition.condi})
     </when>
     <otherwise>
     and 1=0
     </otherwise>
  </choose>

拼接完成的查询sql:

接口优化后比之前的查询性能提高了2-3倍,整个业务系统几乎都是这样的基于树结构数据的查询统计,那么对于整个系统还是有不小的影响

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2036348.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图论(二):图的度分析——度数bar图度数等级图度数直方图根据度数渲染节点颜色

本期所用数据集&#xff0c;空手道俱乐部关系数据集&#xff1a; 数据集中共有34个节点&#xff0c;每个节点代表俱乐部中的一名成员数据集中共有78条边&#xff0c;每条边表示两名成员之间的友谊关系或社交联系常见数据集格式为GML和TXT格式&#xff0c;还可能包含其他格式的…

检索增强生成算法

检索增强生成算法&#xff08;Retrieval-Augmented Generation&#xff0c;RAG)是由Patrick Lewis等人于2020年提出的&#xff08;https://arxiv.org/pdf/2005.11401&#xff09;&#xff0c;主要用于辅助大规模语言模型&#xff08;Large Language Models, LLMs&#xff09;在…

【网络】代理服务器

目录 正向代理 反向代理 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 正向代理 正向代理&#xff08;Forward Proxy&#xff09;是一种常见的网络代理方式&#xff0c;它位于客户端和目标 服务器之间&#xff0c;代表客户端向目标服务器发送请求。正向代理服务器接收客户…

晓北斗 - 北斗七星、北斗导航系统

北斗导航 北斗卫星导航 芯片、模块、天线、板卡等基础产品,是北斗系统应用的基础。通过卫星导航专项的集智攻关,我国实现了卫星导航基础产品的自主可控,形成了完整的产业链。 北斗卫星导航系统&#xff08;Beidou Navigation Satellite System&#xff0c;简称&#xff1a;BD…

Effective-Java-Chapter5-泛型

https://github.com/clxering/Effective-Java-3rd-edition-Chinese-English-bilingual/blob/dev/Chapter-5/Chapter-5-Introduction.md 准则一 不要使用原始类型 首先来看一下什么是原始类型呢&#xff1f; List 对应的原始类型是 List&#xff0c;那其实就是说不带参数化类…

Selenium + Python 自动化测试13(HTML报告)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 上一篇我们讨论了unittest中discover 的构建&#xff0c;可以组织测试更多测试用例。 本篇文章我们接着讲。如何生成HTML报告&#xff0c;提高我们测试报告的可读性。 1、引入…

IOS 01 CocoaPods 安装与使用

什么是CocoaPods CocoaPods是一个依赖管理工具&#xff0c;类似Java语言的Maven&#xff0c;Gradle这样的工具&#xff1b;只是他是管理iOS&#xff0c;macOS等平台项目的依赖而已。 同类软件 Carthage&#xff0c;Swift官方提供的Swift Package Manager。 流行程度 Cocoa…

若依框架将Mybatis改成MybatisPlus

1.引入MybatisPlus的maven依赖 <mybatis-plus.version>3.2.0</mybatis-plus.version> <dependencies><!-- mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifac…

国联证券:蛇吞象

券商蛇吞象&#xff0c;难解业绩荒 今天我们来聊——国联证券 重大资产重组预案发布两个半月后&#xff0c;国联证券最新重组方案出炉&#xff0c;作价294.92亿收购民生证券99.26%的股份。 炒了这么久的券商重组&#xff0c;终于迎来实质性落地。 也因为这两家的营收差异&…

PHP多商家营销活动平台系统小程序源码

解锁营销新境界&#xff01;「多商家营销活动平台」让你的品牌火出圈✨ &#x1f680;【聚合力量&#xff0c;共创辉煌】&#x1f680; 在这个竞争激烈的市场中&#xff0c;单打独斗早已不是最佳选择&#xff01;「多商家营销活动平台」横空出世&#xff0c;它像一座桥梁&…

Redis操作--RedisTemplate(一)介绍

一、介绍 1、简介 RedisTemplate 是 Spring Data Redis 提供的一个高级抽象&#xff0c;由 Spring 官方提供的方便操作 Redis 数据库的一个工具类&#xff0c;支持模板设计模式&#xff0c;使得操作 Redis 更加符合 Spring 的编程模型。还支持序列化机制&#xff0c;可以处理…

基于SpringBoot的航空公司管理系统设计与实现,源码、部署+讲解

摘要 随着互联网时代的日益发展&#xff0c;互联网技术得到了广泛的应用。互联网正在经历一场由传统线下管理模式转变为以互联网主导的线上管理模式的深刻变革。在线管理技术犹如雨后春笋一般冒芽而出&#xff0c;这为我们的生活带来了许多变动。 在近些年国内航空业的蓬勃发…

LVS理论知识

目录 1.描述以及工作原理 1.什么是LVS 2.LVS调度算法 1.静态调度算法 1.轮询RR 2.加权轮询WRR 3.目标地址hash---DH 4.源地址hash---SH 2.动态调度算法 1.LC最少连接 2.wlc加权最少连接 3.sed最少期望延迟 4.nq不排队调度算法 5.lblc基于本地最少连接 6.lnlcr带…

BioMistral 7B: 生物医学领域的开源多语言AI模型

人工智能咨询培训老师叶梓 转载标明出处 尽管目前有许多开源的针对健康领域的大模型可供使用&#xff0c;但现有模型在数据隐私风险、模型性能以及多语言支持方面的局限性&#xff0c;限制了它们在医疗领域的应用。为了克服这些限制&#xff0c;研究者们提出了BioMistral&#…

吴恩达机器学习 笔记四十二 基于内容过滤的深度学习

在电影评分的案例中&#xff0c;基于内容过滤的方法需要用到两个向量&#xff0c;一个是来自用户的特征向量Vu,另一个是电影特征的向量 Vm。以用户的特征为例&#xff0c;原始的向量Xu作为一个神经网络的输入&#xff0c;经过几层之后输出一个有32个单元的向量Vu&#xff0c;电…

中芯国际:回暖

业绩稳重向好&#xff0c;半导体周期逆转&#xff1f;或许可以去掉问号。 今天我们来聊国产晶圆代工龙头——中芯国际 半导体复苏的风已经吹了几个月&#xff0c;各家业绩预告亮眼&#xff0c;但只有数据真正落地才能下定结论。而半导体看晶圆代工&#xff0c;晶圆代工看中芯国…

14.1 NumPy基础

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; 工&#x1f497;重&#x1f497;hao&#x1f497;&#xff1a;野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题.…

uni-app 吸顶方案总结

效果 页面级 uni.pageScrollTo 官方文档&#xff1a;https://uniapp.dcloud.net.cn/api/ui/scroll.html#pagescrollto 原生头部导航 uni.pageScrollTo({selector: #tabs,duration: 300 });(推荐)需要兼容自定义头部导航 <template><view id"demo1" :styl…

Sakana.ai 迈向完全自动化的开放式科学发现

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

设计模式-标识域(Identity Field)

目的 为了在内存对象和数据库行之间维护标识而在对象内保存的一个数据库标识域。 关系数据库和内存对象的区别 区分行&#xff1a;关系数据库使用键来区分数据行&#xff0c;而内存对象不需要这样一个键 引用方法&#xff1a;对象系统中通过原始内存位置直接区分对象&#x…