PostgreSQL 服务端本身没有 max_recursive_iterations 配置项,该错误由客户端(如 DBeaver、DataGrip)自行设置的递归深度限制触发;可通过 psql 命令行执行相同 WITH RECURSIVE 语句验证是否为客户端限制。

为什么 PostgreSQL 会报 max_recursive_iterations 错误
这个错误不是 PostgreSQL 内置的报错,而是你用了某些客户端(比如 DBeaver、DataGrip)或中间件自行设置的递归深度限制。PostgreSQL 服务端本身**没有 max_recursive_iterations 这个配置项**,它只认 WITH RECURSIVE 的实际执行行为——比如栈溢出、超时或内存耗尽。当你看到这个报错,基本可以确定是客户端在 SQL 执行前做了预检查或拦截。
如何确认是客户端还是服务端限制
直接在 psql 命令行里跑同样的递归 CTE:
WITH RECURSIVE t(n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 100000 ) SELECT COUNT(*) FROM t;
如果 psql 跑通了,但 DBeaver 报 max_recursive_iterations,那就是客户端干的。DBeaver 默认把递归层数限制设为 1000,DataGrip 是 5000,且不提示你哪来的这个限制。
- DBeaver:打开
Preferences → Editors → SQL Execution → Max recursive iterations,调高或设为 0(禁用) - DataGrip:在
Settings → Database → Query Execution → Recursive CTE max depth修改 - 若用 JDBC,检查连接 URL 是否带
recursiveDepth=xxx参数
服务端真遇到递归撑爆怎么办
即使客户端放行,深层递归也可能触发 PostgreSQL 实际限制,比如:
-
statement_timeout:长递归查太久被中断,报canceling statement due to statement timeout - 内存不足:
work_mem不够导致落盘甚至 OOM,日志里出现out of memory或could not resize shared memory segment - 栈溢出:极深递归(百万级)可能触发底层 C 栈限制,报
stack depth limit exceeded
应对方式不是硬抬限制,而是优化逻辑:
- 加
WHERE n 类显式截断条件,避免意外无限递归 - 把深度优先遍历改成宽度优先(用数组暂存下层 ID,逐批 JOIN),降低栈压力
- 对树形结构,考虑改用
ltree扩展或闭包表,比纯递归 CTE 更稳
递归 CTE 性能差的根本原因
每次迭代都重算上一轮结果集,没有索引可言。比如查某节点所有祖先,WITH RECURSIVE 会从叶子往上反复 JOIN,而 ltree @> 或闭包表一次索引查找就搞定。
如果你发现递归 CTE 在 10 层以内就明显变慢,大概率是缺少合适的索引支撑 ON 条件字段,或者数据分布导致中间结果集爆炸式膨胀。这时候看 EXPLAIN (ANALYZE, BUFFERS) 输出里的 Rows Removed by Filter 和 Actual Total Time 比单纯调大限制更有价值。
真正难调的不是“怎么让递归更深”,而是“怎么让它根本不用那么深”。










