MySQL 8.0的存储过程支持递归调用,但默认情况下递归深度被严格限制,开发者在编写递归存储过程时经常会遇到执行报错的问题,核心原因就是max_sp_recursion_depth系统变量的默认配置不符合递归需求。

max_sp_recursion_depth的作用
max_sp_recursion_depth是MySQL中专门用来控制存储过程递归调用最大深度的系统变量,它的取值决定了存储过程最多可以递归调用自身多少次。默认值为0,意味着存储过程不允许进行任何递归调用,只要执行到递归逻辑就会直接报错。该变量的取值范围是0到255,设置的值越大,允许的递归深度就越深,但也会消耗更多的系统资源。
临时修改max_sp_recursion_depth
如果只是临时需要执行某个递归存储过程,可以在当前会话中临时修改该变量,会话结束后配置会自动失效,不会影响其他连接的使用。
修改步骤
首先查看当前会话的max_sp_recursion_depth取值:
-- 查看当前会话的递归深度限制 SHOW SESSION VARIABLES LIKE 'max_sp_recursion_depth';
然后设置需要的目标值,比如允许递归10层:
-- 设置当前会话递归深度为10 SET SESSION max_sp_recursion_depth = 10;
修改完成后就可以正常执行递归存储过程了,下面是一个简单的递归存储过程示例,用来计算1到n的累加和:
-- 创建递归存储过程计算累加和
DELIMITER //
CREATE PROCEDURE calc_sum(IN n INT, OUT total INT)
BEGIN
-- 递归终止条件,当n为1时直接返回1
IF n = 1 THEN
SET total = 1;
ELSE
-- 递归调用自身,计算n-1的累加和
CALL calc_sum(n - 1, @temp_sum);
SET total = n + @temp_sum;
END IF;
END //
DELIMITER ;
-- 调用存储过程计算1到5的累加和
SET @result = 0;
CALL calc_sum(5, @result);
SELECT @result AS sum_result;
永久修改max_sp_recursion_depth
如果需要让所有会话都生效,或者重启MySQL后配置依然保留,就需要修改MySQL的配置文件,进行永久配置。
操作步骤
首先找到MySQL 8.0的配置文件,Linux系统一般在/etc/my.cnf或者/etc/mysql/my.cnf,Windows系统一般在MySQL安装目录下的my.ini。
在配置文件的[mysqld]区块中添加如下配置:
[mysqld] # 设置存储过程最大递归深度为20 max_sp_recursion_depth = 20
保存配置文件后,重启MySQL服务让配置生效:
- Linux系统执行:systemctl restart mysqld 或者 service mysql restart
- Windows系统可以在服务管理器中重启MySQL服务,或者执行net stop mysql、net start mysql
重启后可以通过全局变量查看确认配置是否生效:
-- 查看全局递归深度限制 SHOW GLOBAL VARIABLES LIKE 'max_sp_recursion_depth';
注意事项
在修改max_sp_recursion_depth时需要注意以下几点:
- 不要设置过大的值,递归深度越深,占用的内存和CPU资源越多,可能会影响数据库的整体性能,甚至导致服务崩溃。
- 递归存储过程必须设置明确的终止条件,避免出现无限递归的情况,否则即使max_sp_recursion_depth设置得再大,也会耗尽资源。
- 修改全局变量需要拥有SUPER权限,普通用户只能修改当前会话的变量值。
- 如果递归逻辑比较复杂,也可以考虑用临时表或者循环的方式替代递归,减少系统资源的消耗。
常见问题排查
如果修改了max_sp_recursion_depth之后还是出现递归报错,可以按照以下步骤排查:
- 确认变量修改是否生效,分别查看会话变量和全局变量的值是否符合预期。
- 检查存储过程的递归终止条件是否正确,是否存在逻辑漏洞导致递归无法终止。
- 查看递归调用的实际深度是否超过了设置的最大值,可以适当调大max_sp_recursion_depth再测试。
- 检查MySQL的错误日志,查看是否有其他相关的报错信息,辅助定位问题。
MySQL_8.0存储过程递归调用max_sp_recursion_depth修改时间:2026-07-03 19:15:28