当前位置: 首页 > news >正文

记一次若依项目组装树型结构数据的效率优化

背景

最近公司的项目使用了若依框架做开发,发现部门管理功能的部门如果有3万笔记录时,查询部门信息并组装为父子结构时运行特别缓慢,本地运行需要3分钟才能加载出来,因此接到优化的工作。

代码展示

  1. 首先看看表结构是这么定义的(下列代码仅保留当前博文分析的内容)
create table sys_dept (dept_id           bigint(20)      not null auto_increment    comment '部门id',parent_id         bigint(20)      default 0                  comment '父部门id',ancestors         varchar(50)     default ''                 comment '祖级列表',dept_name         varchar(30)     default ''                 comment '部门名称',order_num         int(4)          default 0                  comment '显示顺序',status            char(1)         default '0'                comment '部门状态(0正常 1停用)'-- 省略其他字段primary key (dept_id)
) engine=innodb auto_increment=1 comment = '部门表';
  1. 父子结构的类对象如下
public class TreeSelect implements Serializable {/** 节点ID */private Long id;/** 节点名称 */private String label;/** 子节点 */private List<TreeSelect> children;// 省略setter/getter等其他内容
}
  1. 查询数据就是简单的把sys_dept表内容全查出来,然后在java中遍历每行找到子级,找子级的代码如下
/*** 建立部门树型结构数据, 用于前端使用el-tree进行展示* @param depts 所有部门结果集*/
public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts) {List<SysDept> deptTrees = buildDeptTree(depts);return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
}
/*** 找到每个部门记录的子级集合, 建立部门树型结构* @param dept 查询条件*/
public List<SysDept> buildDeptTree(List<SysDept> depts) {List<SysDept> returnList = new ArrayList<SysDept>();List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());for (SysDept dept : depts) {// 如果是顶级节点, 遍历该父节点的所有子节点if (!tempList.contains(dept.getParentId())) {recursionFn(depts, dept);returnList.add(dept);}}if (returnList.isEmpty()) {returnList = depts;}return returnList;
}
/*** 递归列表*/
private void recursionFn(List<SysDept> list, SysDept t) {// 得到子节点列表List<SysDept> childList = getChildList(list, t);t.setChildren(childList);for (SysDept tChild : childList) {if (hasChild(list, tChild)) {recursionFn(list, tChild);}}
}
/*** 得到子节点列表*/
private List<SysDept> getChildList(List<SysDept> list, SysDept t) {List<SysDept> tlist = new ArrayList<SysDept>();Iterator<SysDept> it = list.iterator();while (it.hasNext()) {SysDept n = (SysDept) it.next();if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) {tlist.add(n);}}return tlist;
}/*** 判断是否有子节点*/
private boolean hasChild(List<SysDept> list, SysDept t) {return getChildList(list, t).size() > 0;
}

问题分析

通过分析上面的代码可以得出以下问题:

  1. 使用List集合进行查找,时间复杂度高:buildDeptTree中先通过遍历获取所有主键到List集合中,用于后面再次遍历时用contains判断是否有父级元素在查询结果集中,此处的List<Long> tempList如果用Set类型来去重和查找元素效率会更高,因为List查找的时间复杂度是O(n)Set的时间复杂度为O(1)
  2. 重复获取子元素:在recursionFn中的hasChild()方法判断是否存在子元素是再执行一遍getChildList()方法遍历获取所有子级,然后判断子级的长度,此处感觉白白花费了比较多时间
  3. 通过List集合遍历获取子元素效率比较低,要获取每个元素的子级,每次都要遍历所有元素

解决思路

  1. 问题1,将List修改为Set即可
  2. 问题2和3,既然用List找到子级遍历很慢,能不能也用Set集合来减少遍历的次数,将查询出的数据按父级(parentId)分组,分组后的对象为groupByParentIdDepts,这样一来分组后的值就是每个父级的子元素,获取每个元素的子级只需要一次遍历:用当前元素的deptId作为键就能直接取到子元素,而判断是否有子元素也不用每次都遍历了,直接通过groupByParentIdDepts获取值的长度大于0即可。

代码修改

修改的内容就集中在buildDeptTreerecursionFn两个方法了(想直接获取修改后的项目代码可以看文章最后的相关链接哈~)

public List<SysDept> buildDeptTree(List<SysDept> depts) {List<SysDept> returnList = new ArrayList<SysDept>();List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());// 按父级分组Map<Long, List<SysDept>> groupByParentIdDepts = depts.stream().filter(dept -> dept.getParentId() != null).collect(Collectors.groupingBy(SysDept::getParentId));for (SysDept dept : depts) {// 如果是顶级节点, 遍历该父节点的所有子节点if (!tempList.contains(dept.getParentId())) {recursionFn(groupByParentIdDepts, dept);returnList.add(dept);}}if (returnList.isEmpty()) {returnList = depts;}return returnList;
}private void recursionFn(Map<Long, List<SysDept>> groupByParentIdDepts, SysDept t) {// 得到子节点列表List<SysDept> childList = groupByParentIdDepts.get(t.getDeptId());if (childList != null) {t.setChildren(childList);// 为每个子节点递归找到子节点for (SysDept tChild : childList) {recursionFn(groupByParentIdDepts, tChild);}} else {t.setChildren(new ArrayList<>(0));}
}
// hasChild方法也可以直接省略了。

总结

  1. 这次的优化其实有点空间换时间的意思,将每次遍历的元素缓存到Map中,然后再通过Map去快速获取子级元素,不知道上面的表述有没有说的够清楚。
  2. 再就是这个框架大大减少了我们开发后台系统的开发时间,有一点小问题也是瑕不掩瑜;毕竟当数据量低的时候感知不大,前期开发者可能也没想到有这么大数据量的部门,为了开发效率也无可厚非啦。
  3. 另外前端接收那么大数据怎么展示呢,我们是引入了@wchbrad/vue-easy-tree虚拟加载树组件来展示的,不然前端也要卡顿好久,这里就不过多阐述了,下文也有链接,可以直接跳转查看官方文档

大家有不同的见解都可以留下你们的评论哈,或者直接到gitee上直接拉取修改也行。

相关链接

若依gitee
在gitee克隆后修改的代码
el-tree虚拟加载树组件:vue-easy-tree

相关文章:

记一次若依项目组装树型结构数据的效率优化

背景 最近公司的项目使用了若依框架做开发&#xff0c;发现部门管理功能的部门如果有3万笔记录时&#xff0c;查询部门信息并组装为父子结构时运行特别缓慢&#xff0c;本地运行需要3分钟才能加载出来&#xff0c;因此接到优化的工作。 代码展示 首先看看表结构是这么定义的…...

秒杀系统之系统优化

3 系统优化 对于一个软件系统&#xff0c;提高性能可以有很多种手段&#xff0c;如提升硬件水平、调优JVM 性能&#xff0c;这里主要关注代码层面的性能优化—— 减少序列化&#xff1a;减少 Java 中的序列化操作可以很好的提升系统性能。序列化大部分是在 RPC 阶段发生&#x…...

【介绍下Python多线程,什么是Python多线程】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…...

FPGA相关论文阅读

一、Achieving 100Gbps Intrusion Prevention on a Single Server 论文名称中文翻译&#xff1a;在单台服务器上实现100Gbps吞吐量的入侵防御检测。 文章中的Mixed-1和Norm-1 二、Distributed Password Hash Computation on Commodity Heterogeneous Programmable Platforms…...

瑞芯微RK3588驱动设计之DVP并口摄像头2

dts配置看瑞芯微RK3588驱动配置之DVP并口摄像头1_rockchip 调试dvp设备 直接显示摄像头数据-CSDN博客 这里看看驱动的具体实现&#xff0c;以gc2145为例。 gc2145的驱动源码如下&#xff1a; // SPDX-License-Identifier: GPL-2.0 /** GC2145 CMOS Image Sensor driver*** C…...

安卓手机APP开发__支持64位的架构

安卓手机APP开发__支持64位的架构 目录 概述 读取你的APP 快速的状态检查 你的APP使用了原生的代码吗&#xff1f; 你的APP包含了64位的代码库吗&#xff1f; 确保在这些目录中有原生的代码库. 使用APK分析器查看原生的代码库 通过解压缩APK查看原生的代码库 用安卓工…...

Foxmail使用经验总结

目录 1.概述 2.版本历史 3.使用方法 3.1.安装和设置账户 3.2.收取和阅读邮件 ​​​​​​​3.3.发送邮件 ​​​​​​​3.4.管理联系人 ​​​​​​​3.5.日程安排和任务管理 ​​​​​​​3.6.定制设置和插件 ​​​​​​​3.7.跨平台同步 4.小结 1.概述 Fox…...

信息系统项目管理师0601:项目立项管理 — 考点总结(可直接理解记忆)

点击查看专栏目录 项目立项管理 — 考点总结(可直接理解记忆) 1.项目建议书(又称立项申请)是项目建设单位向上级主管部门提交项目申请时所必须的文件,是对拟建项目提出的框架性的总体设想。在项目建议书批准后,方可开展对外工作(掌握)。 2.项目建议书应该包括的核心内…...

实验三:机器学习1.0

要求&#xff1a; 针对实验1和实验2构建的数据集信息分析 设计实现通过数据简介进行大类分类的程序 代码实现&#xff1a; 训练集数据获取&#xff1a; read_data.py import json import pickledef read_intro():data []trypathr"E:\Procedure\Python\Experiment\f…...

Vue 3 + Vite项目实战:常见问题与解决方案全解析

文章目录 一、项目使用本地图片打包后不显示1、在html中时候&#xff0c;本地运行和打包后线上运行都ok。2、用动态数据&#xff0c;本地运行ok&#xff0c;打包后线上运行不显示3、适用于处理单个链接的资源文件4、用动态数据且本地和线上访问都可显示 二、使用插件vite-plugi…...

飞天使-k8s知识点31-rancher的正确打开方式

文章目录 安装之前优化一下内核参数以及系统内核版本 rancher安装主要是使用以下命令nginx的配置为解决办法 安装之前优化一下内核参数以及系统内核版本 内核版本 4.17 cat > /etc/modules-load.d/iptables.conf <<EOF ip_tables iptable_filter EOF 然后重启服务器…...

Vue.component v2v3注册(局部与全局)组件使用详解

在Vue中&#xff0c;可以通过两种方式注册组件&#xff1a;局部注册和全局注册。 局部注册是在父组件中通过import和components选项注册的组件&#xff0c;仅在当前父组件及其子组件中可用。 // 父组件中import ChildComponent from ./ChildComponent.vue;export default {co…...

HNU-算法设计与分析-作业5

第五次作业【回溯算法】 文章目录 第五次作业【回溯算法】<1> 算法分析题5-3 回溯法重写0-1背包<2> 算法分析题5-5 旅行商问题&#xff08;剪枝&#xff09;<3> 算法实现题5-2 最小长度电路板排列问题<4> 算法实现题5-7 n色方柱问题<5> 算法实现…...

基础之音视频2

01 前言 02 mp 03 mp实例 简易音乐播放器 04 音频 sound-pool 1.作用 播放多个音频&#xff0c;短促音频 2.过程 加载load- 3.示例 模拟手机选铃声 步骤&#xff1a; 创建SoundPool对象&#xff0c;设置相关属性 音频流存入hashmap 播放音频 05 videoview 3gp 体积小 mp4 …...

两小时看完花书(深度学习入门篇)

1.深度学习花书前言 机器学习早期的时候十分依赖于已有的知识库和人为的逻辑规则&#xff0c;需要人们花大量的时间去制定合理的逻辑判定&#xff0c;可以说是有多少人工&#xff0c;就有多少智能。后来逐渐发展出一些简单的机器学习方法例如logistic regression、naive bayes等…...

21【Aseprite 作图】画白菜

1 对着参考图画轮廓 2 缩小尺寸 变成这样 3 本来是红色的描边&#xff0c;可以通过油漆桶工具&#xff08;取消 “连续”&#xff09;&#xff0c;就把红色的轮廓线&#xff0c;变成黑色的 同时用吸管工具&#xff0c;吸取绿色和白色&#xff0c;用油漆桶填充颜色 4 加上阴影…...

2024.05.15 [AI开发配环境]个人使用最新版远程服务器配环境大纲:docker、云盘、ssh、conda等

不包括在宿主机安装docker。 docker 找到心仪的镜像&#xff0c;比如从网上pull&#xff1a;https://hub.docker.com/r/pytorch/pytorch/tags?page&page_size&ordering&name2.0.1 docker pull pytorch/pytorch:2.0.1-cuda11.7-cudnn8-devel# 新建容器 docker r…...

opencv 轮廓区域检测

直线检测 void LineDetect(const cv::Mat &binaryImage) {cv::Mat xImage,yImage,binaryImage1,binaryImage2;// 形态学变化&#xff0c;闭操作 先膨胀&#xff0c;再腐蚀 可以填充小洞&#xff0c;填充小的噪点cv::Mat element cv::getStructuringElement(cv::MORPH_RE…...

2024-5-16

今日安排&#xff1a; 完结 nf_tables 模块的基本学习&#xff0c;然后开始审计源码mount 的使用&#xff0c;学习 namespace (昨昨昨昨天残留的任务)&#xff08;&#xff1a;看我能搁到什么时候静不下心学习新知识就做 CTF 题目&#x1f991;&#x1f991;&#x1f991; 今…...

IT行业的现状与未来:技术创新引领时代变革

随着技术的不断进步&#xff0c;IT行业已成为推动全球经济和社会发展的关键力量。从云计算、大数据、人工智能到物联网、5G通信和区块链&#xff0c;这些技术正在重塑我们的生活和工作方式。本文将探讨当前IT行业的现状及未来发展趋势&#xff0c;并邀请行业领袖、技术专家和创…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链&#xff08;Filter Chain&#xff09;&#xff0c;核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤&#xff1a; 用户提交登录请求拦…...

全面解析数据库:从基础概念到前沿应用​

在数字化时代&#xff0c;数据已成为企业和社会发展的核心资产&#xff0c;而数据库作为存储、管理和处理数据的关键工具&#xff0c;在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理&#xff0c;到社交网络的用户数据存储&#xff0c;再到金融行业的交易记录处理&a…...