mysql存储过程递归需先查@@max_sp_recursion_depth值,其默认为0即禁用;设值须在会话中执行或过程开头设置,且需配合明确终止条件、防环逻辑及版本兼容性验证。

查当前 max_sp_recursion_depth 值再动手
MySQL 存储过程递归不是默认开的——@@max_sp_recursion_depth 默认是 0,意味着直接禁止递归。不查就设,容易误判问题根源。
运行这条语句确认现状:SELECT @@max_sp_recursion_depth;
- 返回 0:递归被禁用,必须显式设置才生效
- 返回正整数(比如 100):说明已开启,但得看是否真够用
- 注意:该变量是会话级,连接断开即失效;全局生效要改
my.cnf并重启
设值必须在存储过程内部或调用前执行
很多同学把 SET @@max_sp_recursion_depth = 100; 写在 CREATE PROCEDURE 外面,结果调用时还是报错 Error Code: 1456。原因很简单:存储过程体里没设,每次执行都按会话当前值走,而新建连接默认还是 0。
- 安全写法是在存储过程开头加:
SET @@max_sp_recursion_depth = 20; - 或者在调用前手动执行一次:
SET SESSION max_sp_recursion_depth = 20;,再CALL your_proc(...); - 别设太高,业务树形结构(如部门、类目)通常 20 层内封顶;设成 1000 不解决数据环问题,只让报错更慢
递归过程里没退出条件照样爆栈
光调大深度没用。如果递归逻辑里没判断终止(比如没检查 pid IS NULL 或没限制层级计数),哪怕只设了 5,只要数据有自环(A→B→A),第一次递归就卡死或直接溢出。
- 必须在递归调用前加判断,例如:
IF pid IS NULL OR nLevel >= 20 THEN LEAVE proc_label; END IF; - 游标循环中也要配合
STOP标志和异常处理器,否则空结果集也会继续调用 - 测试时一定要用最深路径+人工构造环的数据跑一遍,不能只信“理论上不会超”
云数据库和低版本 MySQL 的隐藏坑
阿里云 RDS、腾讯云 TDSQL 等托管服务,即使显示版本是 8.0.26,也可能阉割或延迟支持 max_sp_recursion_depth 控制。更麻烦的是 MySQL 5.7 及更早版本——压根不认这个变量,设了也无效。
- 先执行
SELECT VERSION();,确认是8.0.16+且非兼容模式 - 若版本不够,只能用临时表 + 循环模拟递归,或把树遍历逻辑提到应用层
- 云环境建议直接查服务商文档,关键词搜 “
max_sp_recursion_depth支持情况”,别依赖控制台显示的版本号











