SQL Server递归CTE深度超限必须显式加OPTION(MAXRECURSION n)且置于最终SELECT末尾,因该限制是解析器硬上限,sp_configure和-T2510对其无效;默认100层即中断,不返回结果。

SQL Server 存储过程中递归 CTE 深度超限,不能靠配置项或跟踪标志调整,必须显式加 OPTION (MAXRECURSION n) 且位置正确;否则默认 100 层一到就报错中断,不返回任何结果。
为什么 sp_configure 和 -T2510 都无效
SQL Server 对递归深度的限制发生在查询编译阶段,是解析器调用栈硬上限,和运行时配置无关:
-
sp_configure 'nested triggers'只控制触发器是否能嵌套触发,和 CTE 完全无关 -
-T2510跟踪标志只影响存储过程嵌套层级,对 CTE 递归无作用 - 视图、函数、存储过程、CTE 共享同一套 32 层嵌套计数(指对象引用链),但 CTE 自身递归层数另算,默认 100
- SSMS 查询设计器或某些 ORM(如 EF 原始 SQL 封装)可能悄悄包裹你的语句,实际嵌套比你写的多 2–3 层
如何正确设置 MAXRECURSION
OPTION (MAXRECURSION n) 必须紧贴最终 DML 语句末尾,且只能作用于该语句;写错位置等于没写:
- ✅ 正确:
SELECT * FROM TreeCTE OPTION (MAXRECURSION 500); - ❌ 错误:
WITH TreeCTE AS (...) OPTION (MAXRECURSION 500) SELECT * FROM TreeCTE;(提示被忽略) - ❌ 错误:
SELECT * FROM TreeCTE UNION ALL SELECT ... OPTION (MAXRECURSION 500);(不在最终语句末尾) -
n取值范围是 0–32767;0表示不限制,但生产环境禁用——数据有环会卡死会话、耗尽内存 - 建议把
@maxRecursion设为存储过程输入参数,由调用方按业务场景传入(如“最多查 6 级部门”就传 6)
常见报错与对应修复点
遇到深度超限,别急着调高数值,先确认是不是语法或逻辑问题导致提前失败:
-
The maximum recursion 100 has been exhausted:说明没加OPTION或位置错,不是数据真有 101 层 -
Msg 319, Level 15:CTE 中锚点和递归成员顺序反了(锚点必须在UNION ALL左侧) - 查询返回空或部分结果:可能是递归 JOIN 条件写反(如写成
e.id = cte.parent_id而非e.parent_id = cte.id),导致无法推进层级 - 执行计划里 “Recursive Union” 下扫描行数暴增:说明锚点或递归分支没走索引,
ParentID字段必须建索引
真正危险的是数据环,不是深度不够
设 MAXRECURSION 1000 解决不了自环问题。比如 device_id = 14 → port_id = 14 这种父子 ID 相同的情况,1 层就死循环:
- 上线前必须检查显式环:
SELECT 1 FROM t t1 JOIN t t2 ON t1.id = t2.parent_id AND t2.id = t1.parent_id - 递归 CTE 内部加防环字段,例如
level < 20或id != ALL(path)(PostgreSQL) - 业务写入时校验,如部门树强制
level <= 6,在应用层或触发器拦截非法插入 - 路径检测比深度限制更关键——深度只是兜底,环才是根因

















