贝利信息

SQL 递归查询的性能风险

日期:2026-01-25 00:00 / 作者:舞夢輝影
递归查询易因缺失索引或深度过大引发全表扫描、栈溢出或超时;应为id/parent_id建索引、避免非SARGable条件、设MAXRECURSION、防环、压测真实数据。

递归查询容易触发全表扫描

SQL 递归(比如 WITH RECURSIVE)在没有合适索引支撑时,每次迭代都可能回表查父/子记录,导致实际执行计划里出现多次 Seq Scan 或等价的全表遍历。尤其当树深度大、分支多,而连接字段(如 parent_id)没建索引时,性能会断崖式下降。

实操建议:

深度过大引发栈溢出或超时

不同数据库对递归层级有硬性限制:PostgreSQL 默认 max_recursion_depth = 100(需通过 SET 调整),SQL Server 默认 100 层,超出直接报错 Maximum recursion exceeded;MySQL 8.0+ 虽无硬限制,但深度大时内存增长快,易被 max_execution_time 或 OOM kill。

实操建议:

重复计算导致结果膨胀和内存飙升

递归 CTE 默认是 UNION ALL 语义,如果父子关系存在环(如 A→B→C→A),或数据本身有冗余路径(如组织架构中某人同时属两个部门),就会无限生成重复行,最终返回几万甚至百万行——而你只想要 10 个节点。

实操建议:

递归查询不是不能用,而是很容易在数据稍不规整、索引稍不匹配、深度稍不收敛时,从“方便”变成“阻塞”。真正上线前,一定要用真实数据量 + 真实深度压测,而不是只在 10 行测试数据上验证逻辑。