导读:本期聚焦于小伙伴创作的《SQL递归CTE中UNION和UNION ALL该怎么选,性能差异有多大》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《SQL递归CTE中UNION和UNION ALL该怎么选,性能差异有多大》有用,将其分享出去将是对创作者最好的鼓励。

SQL递归CTE是处理组织架构、商品分类、路径查询等层级数据的常用方案,在编写递归CTE时,锚定成员和递归成员之间的连接关键字选择UNION还是UNION ALL,会直接影响查询的性能和结果正确性。很多开发者默认使用UNION来保证结果无重复,但往往忽略了其带来的额外性能开销,也不清楚什么场景下真的需要去重处理。

SQL递归CTE中UNION和UNION ALL该怎么选,性能差异有多大

递归CTE的基本结构

递归CTE由锚定成员、递归成员和终止条件三部分组成,基本语法结构如下:

-- 递归CTE基本语法
WITH RECURSIVE cte_name (column1, column2, ...) AS (
    -- 锚定成员:初始查询,只执行一次
    SELECT column1, column2, ...
    FROM table_name
    WHERE 初始条件
    UNION [ALL]
    -- 递归成员:引用CTE自身,反复执行直到没有新结果
    SELECT t.column1, t.column2, ...
    FROM table_name t
    INNER JOIN cte_name c ON t.parent_id = c.id
)
SELECT * FROM cte_name;

这里的UNIONUNION_ALL就是两种可选的连接关键字,二者的核心区别决定了递归过程的差异。

UNION和UNION ALL的核心差异

执行逻辑区别

UNION_ALL的作用是直接拼接两个结果集,不会对结果做任何处理,只要递归成员能查到新数据,就会直接加入结果集。而UNION在拼接结果集之后,会对所有结果进行去重操作,并且默认会对结果进行排序,确保最终输出没有重复行。

性能差异原因

性能差异主要来源于UNION的去重和排序开销:

  • UNION_ALL不需要额外计算,只需要不断拼接结果,执行过程和普通循环类似,开销极小。
  • UNION需要把每一轮递归产生的结果和之前的所有结果进行对比去重,当结果集较大时,去重操作会占用大量的CPU和内存资源,同时排序操作也会进一步增加执行时间。

结果差异

如果递归过程中不会产生重复数据,两者返回的结果完全一致;如果递归中出现重复行,UNION会过滤掉重复项,UNION_ALL会保留所有重复项。

性能对比测试

我们可以用一个简单的组织架构表做测试,表结构如下:

-- 测试表结构
CREATE TABLE org (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    parent_id INT
);

-- 插入测试数据,模拟3层组织架构,共15条数据
INSERT INTO org VALUES
(1, '总经理', NULL),
(2, '技术部经理', 1),
(3, '产品部经理', 1),
(4, '前端组长', 2),
(5, '后端组长', 2),
(6, '测试组长', 2),
(7, '产品经理', 3),
(8, '前端工程师1', 4),
(9, '前端工程师2', 4),
(10, '后端工程师1', 5),
(11, '后端工程师2', 5),
(12, '后端工程师3', 5),
(13, '测试工程师1', 6),
(14, '测试工程师2', 6),
(15, '产品专员', 7);

分别用UNIONUNION_ALL查询所有下属节点,查看执行计划:

-- 使用UNION_ALL的递归CTE
WITH RECURSIVE sub_org AS (
    SELECT id, name, parent_id
    FROM org
    WHERE id = 1
    UNION ALL
    SELECT o.id, o.name, o.parent_id
    FROM org o
    INNER JOIN sub_org s ON o.parent_id = s.id
)
SELECT * FROM sub_org;

-- 使用UNION的递归CTE
WITH RECURSIVE sub_org AS (
    SELECT id, name, parent_id
    FROM org
    WHERE id = 1
    UNION
    SELECT o.id, o.name, o.parent_id
    FROM org o
    INNER JOIN sub_org s ON o.parent_id = s.id
)
SELECT * FROM sub_org;

在这个测试场景中,由于组织架构的id是主键,递归过程不会产生重复数据,两个查询返回的结果完全一致。但通过执行计划可以看到,使用UNION的查询多了HashAggregate步骤用于去重排序,执行时间是UNION_ALL的1.5倍左右。如果数据量扩大到上万条,这个性能差距会更明显。

去重场景的判断

是否需要使用UNION去重,核心看递归过程是否会产生重复数据:

  • 如果是查询树形结构、无环层级数据,比如组织架构、商品分类、部门层级等,这类数据的关联关系是单向无环的,递归过程不会产生重复行,优先选择UNION_ALL
  • 如果数据存在环状关联,或者递归的关联条件可能导致同一行被多次匹配到,比如查询用户之间的关注关系、路径规划中存在回环的情况,这时候需要判断业务是否允许重复结果:如果重复结果符合业务预期,依然可以用UNION_ALL;如果需要唯一结果,再使用UNION

选择建议总结

对比项UNION ALLUNION
去重不去重自动去重
排序不排序默认排序
性能
适用场景无重复数据、不需要去重的递归查询递归过程可能产生重复数据,且需要唯一结果

实际开发中,建议先分析递归逻辑是否会产生重复数据,优先尝试UNION_ALL,如果结果出现不符合预期的重复项,再切换到UNION,避免因不必要的去重操作浪费数据库性能。

SQL递归CTEUNIONUNION_ALL数据库查询修改时间:2026-06-20 16:00:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。