mysql存储过程不支持递归调用,自调用必报error 1424;max_sp_recursion_depth仅限制跨过程嵌套深度,对自调用无效;树形查询应使用with recursive cte或while循环+临时表模拟。

MySQL 存储过程根本不支持递归调用,CALL proc_name() 自调用一定会报 ERROR 1424 (HY000): Recursive stored procedures are not allowed。这不是“深度受限”,而是语法级硬性禁止——max_sp_recursion_depth 对它完全无效。
为什么 set max_sp_recursion_depth 看起来没用?
这个变量只对合法的跨过程嵌套调用链起作用(比如 proc_a → proc_b → proc_c),不是用来放开自调用的。你写 CALL my_proc(),MySQL 在解析阶段就直接拦截,根本不会走到深度检查那步。
-
ERROR 1424是语法错误,发生在 CALL 解析时 -
ERROR 1456是运行时错误,只出现在合法嵌套超深时(比如 A→B→C→D… 第 11 层) -
SET SESSION max_sp_recursion_depth = 10无效,必须用SET GLOBAL max_sp_recursion_depth = 10 - 该设置重启后丢失,永久生效要写进
my.cnf的[mysqld]段
树形查询该用 WITH RECURSIVE CTE,不是存储过程
所有“查所有子节点”“找上级路径”类需求,都应该用 WITH RECURSIVE ——这是 MySQL 8.0+ 唯一被官方认可、语义清晰、性能可控的方案。
- 必须写
RECURSIVE关键字,漏了会报语法错误 - 递归部分必须有终止条件(如
WHERE t.parent_id = st.id最终无法匹配新行) - 默认最多 1000 层,超限报错可临时调高:
SET SESSION cte_max_recursion_depth = 5000 - 加执行超时更可靠:
SET STATEMENT max_execution_time = 2000 FOR WITH RECURSIVE ... - 关键字段(如
parent_id)必须有索引,否则 5 层就可能从毫秒变秒级
非得在存储过程中封装逻辑?用 WHILE + 临时表模拟
如果必须在事务中批量更新树节点、或需配合 UPDATE/INSERT,那就放弃自调用幻想,改用迭代模拟:
- 先建临时表:
CREATE TEMPORARY TABLE temp_nodes (id INT PRIMARY KEY) - 插入根节点:
INSERT INTO temp_nodes SELECT id FROM tree WHERE id = ? - 用
WHILE ROW_COUNT() > 0 DO ... END WHILE循环:每次把temp_nodes中节点的子节点INSERT IGNORE进来 - 循环退出靠“没新数据插入”,不是靠人工计数——避免漏掉深层节点
- 别在循环里反复查原表,把中间结果缓存在临时表中
真正容易被忽略的是:ERROR 1424 和 ERROR 1456 根本不是一回事,混用解决方案只会让问题更隐蔽;而 WITH RECURSIVE 的终止条件写错,比深度设低更危险——它会导致无限循环,直到超时或栈溢出。











