MySQL 5.7 不支持递归语法,包括递归存储过程和递归CTE,解析器直接报错ERROR 1424;MySQL 8.0 仅通过WITH RECURSIVE CTE支持递归查询,不支持存储过程中自调用,且性能依赖索引、统计信息和递归深度配置。

MySQL 5.7 不支持递归存储过程,所谓“8.0 更快”或“5.7 更慢”的对比本身不成立——这是语法能力的有无问题,不是性能调优问题。
MySQL 5.7 根本无法定义递归存储过程
5.7 解析器在遇到 CALL 自身的语句时会直接报错:ERROR 1424 (HY000): Recursive stored procedures are not allowed.。这不是限制深度或配置开关,而是硬性语法拒绝。任何声称“在 5.7 中跑通了递归 SP”的情况,实际是用了模拟递归(如循环 + 临时表)或误判了调用链。
MySQL 8.0 的递归支持依赖 CTE,且开销明确
8.0 真正支持递归,但仅通过 WITH RECURSIVE 语句实现,**不能在传统 CREATE PROCEDURE 内写递归调用自身**。你必须把递归逻辑写成一条查询,例如:
WITH RECURSIVE tree AS ( SELECT id, parent_id, name FROM org WHERE id = 1 UNION ALL SELECT o.id, o.parent_id, o.name FROM org o INNER JOIN tree t ON o.parent_id = t.id ) SELECT * FROM tree;
这种写法的性能瓶颈很实在:
- 每次迭代都需物化中间结果集,内存消耗随层级指数增长
- 8.0 默认
cte_max_recursion_depth = 1000,超限直接报错ERROR 3636,不像 5.7 那样连入口都没有 - 若未给
parent_id建索引,JOIN 部分会退化为全表扫描,性能断崖式下跌
为什么有人觉得“8.0 递归更慢”?其实是和 5.7 的模拟方案比错了对象
很多线上业务在 5.7 时代用“循环 + 临时表 + 游标”模拟树遍历,虽然代码丑、维护难,但因控制精细(比如每层 fetch 限定 100 行),反而比 8.0 的 CTE 递归更稳。而直接把原来 5.7 的模拟逻辑照搬进 8.0 的 CTE,常因没设 MAXRECURSION 或忽略统计信息更新,导致执行计划崩坏。排查要点:
- 用
EXPLAIN FORMAT=TREE看 CTE 是否走了索引,而非EXPLAIN旧格式 - 确认
ANALYZE TABLE org;已执行——8.0 的 CTE 成本估算极度依赖准确的行数统计 - 避免在 CTE 外层再套复杂聚合,CTE 本身已是物化视图,嵌套会触发二次扫描
真正要注意的不是“哪个版本递归更快”,而是:你在 5.7 里写的“伪递归”是否真有必要迁移到 8.0 的 CTE;如果只是查组织树、菜单树这类固定深度结构,往往用自连接 2–3 层比 CTE 更快也更可控。



















