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

MySQL 中的递归查询:实现与优化

  在处理层次结构数据(如组织架构、分类树、评论回复等)时,递归查询是不可或缺的工具。MySQL 8.0 版本引入了对递归公用表表达式(Common Table Expressions, CTEs)的支持,使得我们可以更加直观和高效地编写递归SQL语句。本文将详细介绍如何在MySQL中使用递归CTE进行查询,并探讨一些性能优化技巧。

一、什么是递归查询?

  递归查询是指在一个查询过程中引用自身结果集的操作。例如,在一个表示员工及其直接下属的关系表中,如果想要获取某位经理的所有直接和间接下属,就需要用到递归查询。传统的做法可能是通过循环或多次联接来实现这一目的,但这样不仅代码复杂度高,而且执行效率低下。而递归CTE则提供了一种简洁且高效的解决方案。

二、语法结构

WITH RECURSIVE 别名 AS (-- 初始查询(锚点成员)SELECT 列名 FROM 表名 WHERE 条件UNION ALL-- 递归查询(递归成员)SELECT 列名 FROM 表名 别名2 WHERE 连接条件 (inner join 别名 on 别名2.id_parent = 别名.id)
)
-- 主查询
SELECT 列名 FROM 别名 WHERE 条件;
  1. WITH RECURSIVE: 定义一个递归 CTE (Common Table Expression),相当于定义一个临时表。
  2. 别名:递归 CTE 的别名,用于在递归查询中引用。
  3. 初始查询(锚点成员): 指定递归的起始点,返回递归的初始结果集。 通常是一个简单的SELECT 查询。
  4. UNION ALL: 将初始查询的结果集和递归查询的结果集合并。 UNION ALL 会保留重复数据, UNION会去重, 递归查询建议使用 UNION ALL
  5. 递归查询(递归成员): 指定递归的规则,返回递归的中间结果集。 通常是一个SELECT 查询,其中会引用 WITH RECURSIVE 定义的别名。
  6. 主查询: 对递归 CTE的结果集进行最终的筛选、排序等操作。

三、示例:构建员工层级关系

  假设我们有一个名为employees的表,其中包含员工ID (emp_id)、姓名(name)以及他们的上级ID (manager_id)。现在我们要找出所有由特定员工管理的直接和间接下属。

##建表
CREATE TABLE employees (emp_id INT PRIMARY KEY,name VARCHAR(100),manager_id INT
);##插入数据
INSERT INTO employees VALUES 
(1, 'Alice', NULL),  -- Alice is the CEO
(2, 'Bob', 1),      -- Bob reports to Alice
(3, 'Carol', 1),     -- Carol reports to Alice
(4, 'Dave', 2),      -- Dave reports to Bob
(5, 'Eve', 2),       -- Eve reports to Bob
(6, 'Frank', 3);     -- Frank reports to Carol##查询所有由Alice管理的员工
##首先选择了根节点(即Alice),然后通过递归部分不断加入她的直接和间接下属,最终得到整个管理层级链。
WITH RECURSIVE subordinates AS (SELECT emp_id, name, manager_id, 0 AS levelFROM employeesWHERE emp_id = 1  -- 根节点:AliceUNION ALLSELECT e.emp_id, e.name, e.manager_id, s.level + 1FROM employees eINNER JOIN subordinates s ON e.manager_id = s.emp_id
)
SELECT * FROM subordinates ORDER BY level;

四、注意事项

  1. 必须使用 UNION ALL: 避免使用 UNION,因为 UNION 会去重,可能导致递归查询提前结束。
  2. 递归查询必须引用 WITH RECURSIVE 定义的别名: 否则无法进行递归。
  3. 注意初始查询的选择: 初始查询是递归的起点,需要根据实际需求选择合适的起始点。
  4. 注意连接条件的编写: 连接条件是递归的关键,需要根据实际表结构和业务逻辑编写正确的连接条件。
  5. 避免无限递归:要确保递归查询能够正常结束,避免无限递归导致性能问题。
  6. 性能优化:对于大数据量的层级数据,需要进行性能优化,例如增加索引,限制递归深度等。
  7. MySQL 版本要求: 递归 SQL 需要 MySQL 8.0或以上版本。

五、性能优化技巧

  虽然递归CTE为处理层次结构数据提供了极大的便利,但在实际应用中我们也需要注意其性能表现。以下是几个可以提高递归查询效率的方法:

  1. 索引优化: 确保递归条件中的字段已经建立了适当的索引。比如,在上面的例子中,manager_id应该有索引,以便加速JOIN操作。此外,对于大型表,考虑创建覆盖索引来减少I/O操作。
  2. 控制递归深度: 默认情况下,MySQL允许的最大递归深度为1000层。如果您知道自己的层级不会超过某个数值,可以通过设置系统变量cte_max_recursion_depth来限制递归次数,从而避免不必要的计算资源浪费。
SET SESSION cte_max_recursion_depth = 5;  -- 设置最大递归深度为5
  1. 减少返回列数: 只选择真正需要的列,避免不必要的数据传输和内存占用。例如,如果我们只需要知道员工的名字和层级信息,那么可以在递归部分仅保留这两列。
  2. 使用临时表缓存中间结果: 对于非常复杂的递归查询,特别是那些涉及大量数据的情况,可以考虑先将递归结果存储到临时表中,然后再进行后续处理。这有助于分担主查询的压力,并可能带来更好的性能提升。
  3. 分析并优化查询计划: 最后,不要忘记利用EXPLAIN命令分析查询执行计划,了解MySQL是如何解析和执行您的递归CTE的。根据输出调整查询逻辑或数据库结构,以达到最佳性能。

相关文章:

MySQL 中的递归查询:实现与优化

在处理层次结构数据(如组织架构、分类树、评论回复等)时,递归查询是不可或缺的工具。MySQL 8.0 版本引入了对递归公用表表达式(Common Table Expressions, CTEs)的支持,使得我们可以更加直观和高效地编写递…...

科家多功能美发梳:科技赋能,重塑秀发新生

在繁忙的都市生活中,头皮健康与秀发养护成为了现代人不可忽视的日常课题。近日,科家电动按摩梳以其卓越的性能和创新设计,赢得了广大消费者的青睐。这款集科技与美学于一身的美发梳,不仅搭载了2亿负离子、6000次/分钟的声波振动等前沿技术,更融入了650nm聚能环红光与415nm强劲蓝…...

JVM面试题解,垃圾回收之“分代回收理论”剖析

一、什么是分代回收 我们会把堆内存中的对象间隔一段时间做一次GC(即垃圾回收),但是堆内存很大一块,内存布局分为新生代和老年代、其对象的特点不一样,所以回收的策略也应该各不相同 对于“刚出生”的新对象&#xf…...

批量修改图片资源的属性。

Unity版本2022.3 如图,比如我们想要修改图片的属性的时候,大部分都是 TextureImporter importer (TextureImporter)AssetImporter.GetAtPath("Assets/1.png"); // 获取文件 importer.xxxxxxx xxxxxxx; // 修改属性到这里没什么问题&#xf…...

WebForms 表单

WebForms 表单 引言 WebForms 是一种用于构建动态网页和Web应用程序的技术,它基于ASP.NET框架。在WebForms中,表单是用户与服务器交互的主要方式。本文将详细介绍WebForms表单的概念、工作原理、常用属性和方法,以及如何优化表单以提升用户体验。 WebForms 表单概述 概念…...

vim 中粘贴内容时提示: -- (insert) VISUAL --

目录 问题现象:解决方法:问题原因: 问题现象: 使用 vim 打开一个文本文件,切换到编辑模式后,复制内容进行粘贴时有以下提示: 解决方法: 在命令行模式下禁用鼠标支持 :set mouse …...

一个功能强大、操作易用的屏幕录制.Net开源工具 草稿箱

推荐一款免费开源的屏幕录制工具,凭借其强大的功能和用户友好的界面,受到非常多人喜欢! 01 项目简介 该工具不仅支持全屏录制,还提供区域录制、游戏录制和摄像头录制等多种模式。不管是录制软件操作、游戏、直播、网络教学、课件…...

深入了解 HTTP 头部中的 Accept-Encoding:gzip、deflate、br、zstd

在现代Web开发中,性能优化是至关重要的一部分。HTTP协议中的Accept-Encoding头部正是为性能提升提供了一个非常有效的方式,它告知服务器客户端能够理解并接收哪些压缩算法的响应内容。在这篇博客中,我们将详细探讨Accept-Encoding头部的作用&…...

【Pytest】结构介绍

1.目录结构介绍 project_root/ │ ├── tests/ # 测试用例存放目录 │ ├── __init__.py │ ├── test_module1.py │ ├── module1.py # 被测试的模块 ├── conftest.py # pytest配置文件,可定义fixture和钩子函数 ├── py…...

27. 【.NET 8 实战--孢子记账--从单体到微服务】--简易报表--报表服务

报表是每个记账应用所具备的功能,要实现报表功能就需要把账本的核心功能(记账)完成,因此报表服务作为本专栏第一部分单体应用开发中最后一个要实现的功能,这一篇文章很简单,我们一起来实现一个简单的报表服…...

JAVASE入门十脚-红黑树,比较器,泛型

红黑树Set,ArrayList数组,LinkedList链表 AVL二叉树 红黑树 插入节点一般是红色 treeSet()底层是treeMap,利用红黑树来实现 package ContainerDemo1;import java.util.Objects;public class PersonDemo {private String name;private int age;public PersonDemo(){}public P…...

总结8..

#include <stdio.h> // 定义结构体表示二叉树节点&#xff0c;包含左右子节点编号 struct node { int l; int r; } tree[100000]; // 全局变量记录二叉树最大深度&#xff0c;初始为0 int ans 0; // 深度优先搜索函数 // pos: 当前节点在数组中的位置&#xff0c…...

RabbitMQ 仲裁队列 -- 解决 RabbitMQ 集群数据不同步的问题

1.问题情景 当我们搭建了一个 RabbitMQ 集群后是存在问题的,也就是数据不同步.我们可以来看下是什么问题 1. 1 添加队列 ①:选择虚拟机(需要保证操作⽤户对当前虚拟机有操作权限) ②:设置队列名称 ③:持久化队列 ④:指定队列所在主节点,其他为从节点分别以 rabbit 节点和 rabb…...

1_相向双指针_leetcode_15_2

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例 1&…...

环境变量配置与问题解决

目录 方法 配置了还是运行不了想要的东西 解决方案 为什么 解决方案 方法 方法一&#xff1a;此电脑右击-属性-相关链接-高级系统设置-环境变量&#xff08;N&#xff09;-系统变量里面找到Path-三个确定】 方法二&#xff1a;winr cmd 黑框输入sysdm.cpl&#xff0c;后面…...

js 数据组合,一级结构组合成父子嵌套数组结构

1.方法 buildDeptTree(deptData) { //构建树状部门// 创建一个 map 来存储 deptId 和对应的部门对象const deptMap new Map();// 初始化每个部门对象的 children 属性为空数组deptData.forEach(dept > {dept.children [];deptMap.set(dept.deptId, dept);});// 构建树形结…...

Python GUI 开发 | PySide6 PyQt6 学习手册

本文是个 Python GUI 开发的目录&#xff0c;方便读者系统性学习的&#xff0c;笔者后续会满满填充此目录中的内容&#xff0c;感兴趣的小伙伴可以关注一手。&#xff08;主要是偏向 PySide6 方向的&#xff09; 0x01&#xff1a;PySide6 & PyQt6 基础入门 0x0101&#xff…...

mysql如何修改密码

在MySQL中修改密码可以通过多种方式完成&#xff0c;具体取决于你的MySQL版本和你是否有足够的权限。以下是一些常用的方法来修改MySQL用户的密码&#xff1a; 方法1: 使用ALTER USER命令 这是最常用的方法&#xff0c;适用于MySQL 5.7及以上版本。 ALTER USER usernameloca…...

Linux 部署 Java 项目:Tomcat、Redis、MySQL 教程

在 Linux 服务器上部署 Java 项目通常需要配置应用服务器&#xff08;如 Tomcat&#xff09;、数据库&#xff08;如 MySQL&#xff09;和缓存服务器&#xff08;如 Redis&#xff09;。本文将详细介绍如何在 Linux 环境中部署一个 Java 项目&#xff0c;涵盖 Tomcat、Redis 和…...

扣子平台音频功能:让声音也能“智能”起来

在数字化时代&#xff0c;音频内容的重要性不言而喻。无论是在线课程、有声读物&#xff0c;还是各种多媒体应用&#xff0c;音频都是传递信息、增强体验的关键元素。扣子平台的音频功能&#xff0c;为开发者和内容创作者提供了一个强大而灵活的工具&#xff0c;让音频的使用和…...

mongoDB常见指令

即使我们自己开发用不到mongoDB&#xff0c;但是接手别人项目的时候&#xff0c;别人如果用了&#xff0c;我们也要会简单调试一下 虽然mongoDB用的不是sql语句&#xff0c;但语句的逻辑都是相似的&#xff0c;比如查看数据库、数据表&#xff0c;增删改查这些 我们下面以doc…...

【线上问题定位处理】及【性能优化】系列文章

目录 性能优化 性能优化 九大服务架构性能优化方式 如何进行GC调优 如何排查线上系统出现的Full GC MySQL - 性能优化 MySQL - 分库分表 大数据查询的处理方案 MySQL优化手段有哪些 服务CPU100%问题如何快速定位? 服务内存OOM问题如何快速定位? JVM调优6大步骤 线…...

实验二 数据库的附加/分离、导入/导出与备份/还原

实验二 数据库的附加/分离、导入/导出与备份/还原 一、实验目的 1、理解备份的基本概念&#xff0c;掌握各种备份数据库的方法。 2、掌握如何从备份中还原数据库。 3、掌握数据库中各种数据的导入/导出。 4、掌握数据库的附加与分离&#xff0c;理解数据库的附加与分离的作用。…...

RubyFPV开源代码之系统简介

RubyFPV开源代码之系统简介 1. 源由2. 工程架构3. 特性介绍&#xff08;软件&#xff09;3.1 特性亮点3.2 数字优势3.3 使用功能 4. DEMO推荐&#xff08;硬件&#xff09;4.1 天空端4.2 地面端4.3 按键硬件Raspberry PiRadxa 3W/E/C 5. 软件设计6. 参考资料 1. 源由 RubyFPV以…...

php代码审计2 piwigo CMS in_array()函数漏洞

php代码审计2 piwigo CMS in_array()函数漏洞 一、目的 本次学习目的是了解in_array()函数和对项目piwigo中关于in_array()函数存在漏洞的一个审计并利用漏洞获得管理员帐号。 二、in_array函数学习 in_array() 函数搜索数组中是否存在指定的值。 in_array($search,$array…...

第25章 测试驱动开发模式深度剖析

写在前面 这本书是我们老板推荐过的&#xff0c;我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后&#xff0c;我突然思考&#xff0c;对于测试开发工程师来说&#xff0c;什么才更有价值呢&#xff1f;如何让 AI 工具更好地辅助自己写代码&#xff0c;或许…...

PHP校园助手系统小程序

&#x1f511; 校园助手系统 —— 智慧校园生活 &#x1f4f1;一款基于ThinkPHPUniapp框架深度定制的校园助手系统&#xff0c;犹如一把智慧之钥&#xff0c;专为校园团队精心打造&#xff0c;解锁智慧校园生活的无限精彩。它独家适配微信小程序&#xff0c;无需繁琐的下载与安…...

转换算术表达式

文章目录 构造二叉树表示的算术表达式&#xff1a;按先序次序输入二叉树中结点的值(操作数及运算符均以一位字符表示&#xff0c;注意转换)&#xff0c; #字符表示空树&#xff0c;如上图的算术表达式 输入2##*3##4## 输入格式 第一行输入表示要计算的算术表达式的二叉树结点的…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.2 ndarray解剖课:多维数组的底层实现

1.2 《ndarray解剖课&#xff1a;多维数组的底层实现》 内容介绍 NumPy 的 ndarray 是其核心数据结构&#xff0c;用于高效处理多维数组。在这篇文章中&#xff0c;我们将深入解析 ndarray 的底层实现&#xff0c;探讨其内存结构、维度、数据类型、步长等关键概念&#xff0c…...

计算机网络 (61)移动IP

前言 移动IP&#xff08;Mobile IP&#xff09;是由Internet工程任务小组&#xff08;Internet Engineering Task Force&#xff0c;IETF&#xff09;提出的一个协议&#xff0c;旨在解决移动设备在不同网络间切换时的通信问题&#xff0c;确保移动设备可以在离开原有网络或子网…...