mysql 查询树形,id与pid关联

目录

[1. 使用递归公用表表达式(推荐 MySQL 8.0+)](#1. 使用递归公用表表达式(推荐 MySQL 8.0+))

[2. 使用自定义函数(适用于 MySQL 5.7及以下)](#2. 使用自定义函数(适用于 MySQL 5.7及以下))

[3. 应用层组装(通用方案)](#3. 应用层组装(通用方案))

[4. 其他高级设计模式(针对高性能需求)](#4. 其他高级设计模式(针对高性能需求))

总结建议‌


如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

在MySQL中查询基于id和pid关联的树形结构数据,主要有以下几种常用方案,可根据MySQL版本及业务需求选择:

1. 使用递归公用表表达式(推荐 MySQL 8.0+)

这是最标准且性能较好的方式,利用 WITH RECURSIVE语法实现递归查询。

‌查询指定节点的所有子级(向下查询):

WITH RECURSIVE tree_cte AS (

-- 锚点成员:指定起始节点

SELECT id, pid, name, 1 as level

FROM tree

WHERE id = 1 -- 替换为指定的父节点ID

UNION ALL

-- 递归成员:查找子节点

SELECT t.id, t.pid, t.name, tc.level + 1

FROM tree t

INNER JOIN tree_cte tc ON t.pid = tc.id

)

SELECT * FROM tree_cte;

查询指定节点的所有父级(向上查询):

WITH RECURSIVE parent_cte AS (

-- 锚点成员:指定起始节点

SELECT id, pid, name

FROM tree

WHERE id = 5 -- 替换为指定的子节点ID

UNION ALL

-- 递归成员:查找父节点

SELECT t.id, t.pid, t.name

FROM tree t

INNER JOIN parent_cte pc ON t.id = pc.pid

)

SELECT * FROM parent_cte;

2. 使用自定义函数(适用于 MySQL 5.7及以下)

在旧版本MySQL中,通常通过创建存储函数,利用循环和 FIND_IN_SET 或 GROUP_CONCAT 来收集所有子节点或父节点的ID字符串,然后再进行查询。

‌获取所有子节点ID的函数示例逻辑:‌

初始化一个包含根节点ID的字符串变量。

循环查询当前层级所有节点的子节点ID。

将新发现的子节点ID拼接到字符串中。

直到没有新的子节点产生为止。

返回ID字符串,外层使用 FIND_IN_SET(id, get_child_ids(root_id)) 进行过滤。

注意:这种方法在数据量较大时性能较差,且受限于 group_concat_max_len 系统变量。

3. 应用层组装(通用方案)

如果数据库查询压力较大或逻辑复杂,可以采用"一次加载,内存组装"的策略:

3.1 SQL查询‌:一次性查询出所有相关节点(或全表),按 pid 或 level 排序。

SELECT * FROM tree ORDER BY pid, id;

‌3.2 代码处理‌ :在Java/Python/Go等后端语言中,遍历列表,利用Map将节点挂载到对应的父节点下。

创建一个 Map<ID, Node>。

遍历所有节点,将节点放入Map。

再次遍历,根据 pid 从Map中找到父节点,将当前节点加入父节点的 children 列表。

筛选出根节点(pid为0或null)作为树的入口。

4. 其他高级设计模式(针对高性能需求)

如果树形结构非常深且查询频繁,可以考虑改变表结构设计:

路径枚举(Path Enumeration)‌ :增加 path 字段(如 0,1,5,10),查询子节点时使用 LIKE '0,1,%'。

闭包表(Closure Table)‌ :新建一张关系表,存储所有祖先-后代关系对,查询时直接Join该表,效率极高但维护成本稍高。

嵌套集(MPTT)‌:增加 lft 和 rgt 字段,通过范围查询获取子树,读取性能极佳,但插入和移动节点时需要更新大量数据。

总结建议‌

如果是 ‌MySQL 8.0+‌,优先使用 ‌方案1(WITH RECURSIVE)‌,语法简洁且由数据库引擎优化。

如果是 ‌MySQL 5.7‌ 且数据量小,可使用 ‌方案2(自定义函数)‌。

如果数据量大且业务逻辑复杂,推荐 ‌方案3(应用层组装)‌,减少数据库递归压力。

如果对读取性能有极致要求且写操作较少,考虑 ‌方案4(闭包表或路径枚举)‌。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

相关推荐
风哥2号22 分钟前
数据库教程FGMT43‑MySQL性能分析与优化调整
数据库·mysql
随身数智备忘录1 小时前
财务数据分析如何与业务场景结合?财务数据分析如何从数出有据到数出有用?
数据库
这个DBA有点耶2 小时前
数据库教程:从零基础到实战的完整学习路径(2026版)
数据库·程序员·代码规范
forestsea3 小时前
从零构建 Java 智能体 RAG 系统:Milvus 向量数据库实战指南
java·数据库·milvus
默 语3 小时前
Java新手入门:从零开始安装JDK并配置环境变量
java·开发语言·python·mysql·group by·1024程序员节·数据去重
probex_3 小时前
从 ByConity 到 VictoriaMetrics:一次指标数据迁移引发的四种存储对比
数据库
用户3074596982073 小时前
MySQL EXPLAIN 零基础完全精通指南:从"看不懂"到"会优化"
mysql
Patrick在香港4 小时前
Python 审计香港开放数据目录:两个端点差 10 倍,只有 9.3% 的资源标了「最后修改时间」
开发语言·数据库·python·数据分析·api·数据治理·开放数据
这个DBA有点耶4 小时前
自增主键用尽了怎么办?INT溢出、在线迁移与预防策略全解析
数据库·mysql·代码规范
迷茫的大专生4 小时前
高可用总结
redis·mysql·nginx·高可用