首页/数据/SQL 速查/递归 CTE 的深度限制与环检测

递归 CTE 的深度限制与环检测

数据成环或条件写错时递归不终止:MySQL 有 cte_max_recursion_depth 保护(默认 1000),PostgreSQL 需要自行加深度或路径防护。

SQL 速查数据更新于 2026-10-13

递归查询的失控风险

递归查询用于处理层级数据:组织架构、目录树、物料清单、多级分类。写法上分成两部分,先取根节点作为起点,再用连接把子节点一层层接上。风险在于数据本身成环或者连接条件写错时,递归永不终止,把数据库连接和内存一起耗尽。MySQL 内置了递归深度上限作为兜底,PostgreSQL 默认没有这层保护,必须自己在语句里加深度判断或路径判断。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
MySQL 保护递归深度参数默认为 1000,超出后语句以递归中止报错结束
PostgreSQL 保护默认无深度上限,需要语句内自行加深度条件
环检测PostgreSQL 14 起支持专门的环检测子句,自动标记并截断
通用做法递归项里累加层级数并限制上限,同时对脏数据做定期巡检

典型使用场景

  • 组织架构展开:从某个部门出发列出所有下级部门与人员
  • 目录或分类树:按父子字段拼出完整层级路径
  • 物料清单展开:算出一件成品需要的全部下级零件数量
  • 影响面分析:给定一个模块,找出所有依赖它的上游服务
  • 层级路径去重:把树的每一层结果拼成可读路径,用于展示或导出

加深度限制的通用写法

加深度限制的通用写法
WITH RECURSIVE org AS (
    SELECT id, manager_id, 1 AS lvl          -- 起点:没有上级的根节点
    FROM employees
    WHERE manager_id IS NULL
    UNION ALL
    SELECT e.id, e.manager_id, o.lvl + 1     -- 递归项:逐层向下展开
    FROM employees e
    JOIN org o ON e.manager_id = o.id
    WHERE o.lvl < 10                         -- 深度上限,防止无限递归
)
SELECT * FROM org;

-- PostgreSQL 14 起的环检测写法
WITH RECURSIVE walk AS (
    SELECT id, parent_id FROM nodes WHERE parent_id IS NULL
    UNION ALL
    SELECT n.id, n.parent_id FROM nodes n JOIN walk w ON n.parent_id = w.id
) CYCLE id SET is_cycle USING path       -- 自动记录路径并标记成环
SELECT * FROM walk WHERE NOT is_cycle;

两层保护对照

保护手段MySQL 行为PostgreSQL 行为
深度上限参数有默认上限,超出报错中止无默认上限,需自己写在语句里
环检测语法无专门语法,用路径条件代替14 起支持专门的环检测子句
超限表现语句失败并给出迭代次数提示不限制时会一直跑,直到资源耗尽
推荐做法深度条件与路径去重一起用深度条件为主,新版可用环检测
看到「递归超过迭代次数」这类报错时,第一反应应该是查数据里有没有环、连接条件是不是写反了,而不是直接把深度参数调大。调大参数只是把报错推迟,真正的环仍然存在,而且每轮迭代都在消耗资源。
如果为了记录路径而在递归里不断拼接字符串,内存占用会随深度线性增长。层级很深的树要谨慎,必要时只保留必要的路径节点或改成逐层落库。

易错点

  • 见到递归报错就直接调大深度参数:环还在,只是把故障推迟到资源被耗尽时才爆发
  • 递归只用 UNION ALL 且没有深度上限:在 PostgreSQL 上会一直跑下去,直到连接被拖垮
  • 用去重替代深度限制:不同层级拼出的路径往往互不相同,去重根本拦不住循环
  • 环检测的路径列随深度增长,深层递归时字符串拼接可能占用大量内存
  • 把层级数据和业务写在同一张事务频繁更新的表上做递归,长查询会与写入相互阻塞

数据来源与参考

  • MySQL 8.0 Reference Manual · Recursive CTE Limits
  • PostgreSQL Documentation · Recursive Queries
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌