mysql 8.0+ 默认递归最大层数为100,通过设置系统变量cte_max_recursion_depth控制,可会话级执行set session cte_max_recursion_depth = 500或全局级set global cte_max_recursion_depth = 500,但不能设为0,且需配合路径防环逻辑。

MySQL 8.0+ 怎么设递归最大层数?
MySQL 默认限制 cte_max_recursion_depth 为 100,超限直接报错 ERROR 3636,而不是卡住——这是安全机制,不是 bug。你得主动调高它,但不能设为 0(无限制)。
两种改法:
- 会话级临时生效:
SET SESSION cte_max_recursion_depth = 500;,之后再跑你的WITH RECURSIVE - 全局永久生效(需 SUPER 权限):
SET GLOBAL cte_max_recursion_depth = 500;,但重启后失效,要写进my.cnf的[mysqld]段里
注意:设太高没用,如果数据本身有环(比如 A→B→C→A),加深度只是拖慢报错时间,不解决根本问题。
PostgreSQL 怎么防递归路径重复?
PG 没有 MAXRECURSION 提示,靠逻辑防环。核心是维护一个 path 字段,每次递归前检查当前节点是否已在路径中。
关键写法:
- 锚点里初始化:
ARRAY[id] AS path - 递归里拼接:
r.path || t.id - WHERE 过滤环:
WHERE t.id != ALL(r.path)
别用字符串拼接(如 ',' || id || ','),容易误匹配(id=1 和 id=11 在逗号分隔下会冲突);ARRAY 类型更安全、性能也更好。
SQL Server 的 OPTION (MAXRECURSION n) 为什么有时不生效?
这个提示只对当前查询生效,但有两个常见坑:
- 放在
UNION ALL后面、SELECT *前面——位置错了就忽略,必须紧贴最终SELECT语句末尾 - CTE 被封装进视图或内联表值函数(ITVF)时,
OPTION提示无法透传,得把提示挪到外层查询上
另外,OPTION (MAXRECURSION 0) 是危险操作,一旦数据有环,可能耗尽内存或触发查询超时,生产环境禁止使用。
为什么光加深度限制还不够?
递归深度只是兜底,真正要命的是数据环。比如设备拓扑里 port_id 14 的 OUT 连回自己(device_id 14 → cable_id 13 → port_id 26 → device_id 14),这种自环 1 层就死循环,设 1000 层也没用。
上线前必须做两件事:
- 用自连接查显式环:
SELECT 1 FROM t t1 JOIN t t2 ON t1.id = t2.parent_id AND t2.id = t1.parent_id - 业务写入时校验层级,比如部门树强制
level ,在应用层或触发器里拦住非法插入
路径检测和深度限制得一起用,缺一不可。










