Oracle MySQL SQL Server 存储过程 C C++ C# JAVA PHP 函数 方法 递归 调用 深度 级数 次数 限制

版权声明:本文为博主原创文章,转载请申明原文出处。 https://blog.csdn.net/xuheng8600/article/details/85334909

Oracle

问题举例:

原文:https://bbs.csdn.net/topics/10479391?list=lz

ORA-00036: 超过递归 SQL (50) 级的最大值
ORA-06512: 在"SYSTEM.LOGRSAUTHS", line 11
ORA-04088: 触发器 'SYSTEM.LOGRSAUTHS' 执行过程中出错

SQL Server

问题举例:

原文 :https://bbs.csdn.net/topics/390208884      

sql server 2008 存储过程递归层数还是32层么?能修改吗? 

解决方法:

CTE递归层次可以无限制,默认是100
可用OPTION(MAXRECURSION 0) --MAXRECURSION为0时,递归层次无限制,100为系统的默认值。

联机丛书:找这个标题: 使用公用表表达式的递归查询 
 
注意: 
       如果递归 CTE 组合不正确,可能会导致无限循环。例如,如果递归成员查询定义对父列和子列返回相同的值,则会造成无限循环。在测试递归查询的结果时,可以通过在 INSERT、UPDATE、DELETE 或 SELECT 语句的 OPTION 子句中使用 MAXRECURSION 提示和 0 到 32,767 之间的值,来限制特定语句允许的递归级数。有关详细信息,请参阅查询提示 (Transact-SQL) 和 WITH common_table_expression (Transact-SQL)。      

       SQL Server 是MySQL微软收购原班开发团队开发的MySQL近亲版本,它的 max_sp_recursion_depth 问题解决方法同Mysql,见下文。

MySQL 

       MySQL 存储过程递归调用 次数 max_sp_recursion_depth, 在操作系统默认2M(依赖不同的操作系统)的线程堆栈大小下,max_sp_recursion_depth 的可以设置范围为  max_sp_recursion_depth [0, 255],

解决方法:

        存储过程递归增加了对线程堆栈空间的需求。如果增加 max_sp_recursion_depth 的值,则可能需要在服务器启动时通过增加  thread_stack 的值来增加线程堆栈大小。

问题举例:

原文:http://www.gbase8a.com/forum.php?mod=viewthread&tid=987

存储过程递归调用及max_sp_recursion_depth参数配置

存储过程递归调用的时候会引起报错,举例如下:

drop procedure if exists pro_test_1;

delimiter |

create procedure pro_test_1(lvl int)

begin

select '1';

set lvl=lvl-1;

if lvl>=0 then

call pro_test_1(lvl);

end if;

end |

delimiter ;

call pro_test_1(2017);

会产生以下报错信息:

错误:{STATEMENT: call pro_test_1(2017)

INSTRUCTION: call pro_test_1(lvl) [4]}

Recursive limit 0 (as set by the max_sp_recursion_depth variable) was exceeded for routine pro_test_1

回答1

grander发表于2018-8-16 14:50

从字面意思上来看,是超过递归调用的最大深度,可以通过设置集群层的max_sp_recursion_depth 参数解决该问题。

set max_sp_recursion_depth =3000;

call pro_test_1(2017);

执行成功

max_sp_recursion_depth参数范围是[0~255],该值设置超出255后会报错。

当递归层数参数max_sp_recursion_depth 设置为255的情况下,需要相应的调大gcluster层的thread_stack参数(测试环境调整为2M),然后重启gclusterd;否则可能会引起gclusterd的宕机。

原文:http://www.gbase8a.com/forum.php?mod=viewthread&tid=987

       MySQL 存储过程递归调用 次数 max_sp_recursion_depth, 在操作系统默认2M的线程堆栈大小下,max_sp_recursion_depth 的可以设置范围为 [0, 255],参考Mysql官方文档:

https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html

max_sp_recursion_depth

Property Value
Command-Line Format --max-sp-recursion-depth[=#]
System Variable max_sp_recursion_depth
Scope Global, Session
Dynamic Yes
Type Integer
Default Value 0
Maximum Value 255

   The number of times that any given stored procedure may be called recursively. The default value for this option is 0, which completely disables recursion in stored procedures. The maximum value is 255.

   Stored procedure recursion increases the demand on thread stack space. If you increase the value of max_sp_recursion_depth, it may be necessary to increase thread stack size by increasing the value of thread_stack at server startup.

       递归调用任何给定存储过程的次数。此选项的默认值为0,它完全禁用存储过程中的递归。最大值为255。

       存储过程递归增加了对线程堆栈空间的需求。如果增加 max_sp_recursion_depth 的值,则可能需要在服务器启动时通过增加  thread_stack 的值来增加线程堆栈大小。

增加线程堆栈大小方法:

原文:http://codenuggets.com/2013/12/02/mysql-recursive-procedure/

CODENUGGETS

MySQL Recursive Procedure

Dec 2, 2013

I’m trying to write a recursive stored procedure or function to auto-generate large amount of hierarchical (tree) data for dissertation experiment.

What I find out is that, in MySQL, only recursive stored procedure is allowed, where stored function is not allowed. So, the following procedure works:

delimiter //
create procedure rec_seq(min int, max int, result text)
begin
	-- Put current value into result
	set result = concat(result, min);
	if min != max then
		set result = concat(result, ' ');
	end if;
	
	if min = max then
		-- Output result
		select result;
	else
		-- Recursive call
		call rec_seq(min + 1, max, result);
	end if;
end//
delimiter ;

Where as the following very similar stored function will not run:

delimiter //

create function rec_seq(min int, max int) RETURNS text CHARSET latin1
begin
	if min = max then
		return min;
	end if;

	set @result = '';
	set @result = concat(@result, min);
	set @result = concat(@result, ',');
	set @result = concat(@result, rec_seq(min + 1, max));
	return @result;
end//

To run the stored procedure, we need to increase the max_sp_recursion_depth, which is set to 0 on my installation. To run the procedure, I execute the following:

set max_sp_recursion_depth = 200;
call rec_seq(1,10, '');

This produce the following output:

mysql> call rec_seq(1,10,'');
+----------------------+
| result               |
+----------------------+
| 1 2 3 4 5 6 7 8 9 10 |
+----------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

When I run the stored procedure with range from 1 to 15, even with this simple script I get a stack overflow error:

mysql> call rec_seq(1,12,'');
ERROR 1436 (HY000): Thread stack overrun:  70208 bytes used of a 196608 byte stack, and 128000 bytes needed.  Use 'mysqld --thread_stack=#' to specify a bigger stack.

My solution was to edit /etc/mysql/my.cnf and change thread_stack from 192k to a higher value. The following is my change:

# * Fine Tuning
#
key_buffer              = 16M
max_allowed_packet      = 16M
**thread_stack            = 512K**
thread_cache_size       = 8
# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched

References

http://www.mysqltutorial.org/stored-procedures-parameters.aspx

http://stackoverflow.com/questions/3536538/mysql-does-not-support-recursive-functions-why-since-when

http://stackoverflow.com/questions/8821575/mysql-error-1436-thread-stack-overrun-with-simple-query

原文:http://codenuggets.com/2013/12/02/mysql-recursive-procedure/

代码举例1:存储过程实现递归算法

2016年12月28日 15:08:59 wzy0623 阅读数:2742更多

个人分类: BI

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wzy0623/article/details/53908746

以经典的阶乘算法为例。

Oracle

[sql] view plain copy

  1. create or replace procedure factorial(n in number, b out number)  
  2. is  
  3.     c_in number;  
  4.     c_out number;  
  5. begin  
  6.     if n!=1 then  
  7.         c_in := n-1;  
  8.         factorial(c_in,c_out);  
  9.         b := n*c_out;  
  10.     else  
  11.         b := 1;  
  12.     end if;  
  13. end;  
  14. /  
  15.   
  16. --调用  
  17. variable r number;  
  18. exec factorial(6,:r);  
  19. print r;  

MySQL:

[sql] view plain copy

  1. drop procedure if exists factorial;  
  2. set @@session.max_sp_recursion_depth=99;  
  3. delimiter $$  
  4.   
  5. create procedure factorial (in n bigint, out b bigint)  
  6. begin  
  7.     declare c_in bigint;  
  8.     declare c_out bigint;  
  9.     if n!=1 then  
  10.         set c_in := n-1;  
  11.         call factorial(c_in,c_out);  
  12.         set b:=n*c_out;  
  13.     else  
  14.         set b:=1;  
  15.     end if;  
  16. end$$  
  17.   
  18. delimiter ;  
  19.   
  20. --调用  
  21. call factorial(6,@r);  
  22. select @r;  

https://blog.csdn.net/wzy0623/article/details/53908746

代码举例2:

原文:https://www.cnblogs.com/jagerLan/p/9048747.html

丰兰月

随笔 - 1  文章 - 0  评论 - 0

存储过程的递归调用(树形结构路径的快速生成)

       最近在做表数据整理的时候碰到这样的一个问题,我有一张permission表,其数据结构为树形结构,里面有个permission_path字段用于记录根节点到父节点的路径(以permission_id为路径)。

  例子:假设100的父节点为10,10的父节点为1,这100的路径为:1/10。

  但现在有个问题,permission_path字段在当时并没有处理(为空字符串),如今这个表有四五百条数据,写代码来改太麻烦,更别说一条条数据手动修改,不可行!

  能否通过一个语句块来自动生成路径?显然是可以的,因为现在的oracle、SQL SERVER2005以上版本和mysql5.0以上版本的数据库都支持存储过程,而存储过程还有个比较有趣的玩法,那就是递归调用!用这个方法就可以快速、方便地解决上述问题。

  存储过程的概念这里就不介绍了,语句非常简单,直接上语句(我使用的数据库是mysql5.6),一步步解析:

复制代码

CREATE PROCEDURE test(IN parent int)
BEGIN 
DECLARE ids VARCHAR(255) DEFAULT '0';   
DECLARE IND INT;
DECLARE i INT DEFAULT 1;
DECLARE path VARCHAR(255);
SELECT GROUP_CONCAT(t.permission_id) INTO ids from system_permissions t where t.permission_parent = parent;
SELECT COUNT(t.*) INTO IND from system_permissions t where t.permission_parent = parent;
SELECT t.permission_path INTO path from system_permissions t where t.permission_id = parent;
if ids <> '0' THEN
UPDATE system_permissions set permission_path = CONCAT(path,'/',parent) where permission_parent = parent;
SET @@max_sp_recursion_depth = 100;  
while i <= IND  DO
call test(substring_index(substring_index(ids,',', i), ',', -1));
set i = i + 1;
end while;
end if;
end

复制代码

  先介绍基本语法:

复制代码

create procedure test(IN p1 int,IN p2 varchar2(10))      //create procedure 函数名(IN 参数1 类型,IN 参数2 类型),英文部分为固定写法,
                                    中文部分为自定义,其中类型只能使用数据库存在的类型

  begin   //标识着存储过程逻辑的开始

    语句内容  //逻辑、语句都写在此处

  end  //标识着存储过程逻辑的结束

复制代码

DECLARE 声明变量,
DECLARE ids VARCHAR(255) DEFAULT '0';    //DECLARE 表示声明一个变量,该变量类型为varchar(255),默认值为0

把变量都定义好后,就可以使用sql语句对数据进行操作

在几个select语句之后,会看到if的判断语句,在if中使用update更新表的permissiom_path的值

if ids <> '0' THEN    //if语句的开头,if 判断条件 then
  逻辑内容
end if;    //if语句的结尾

while循环语句,用于循环遍历同级数据,在这个存储过程中也充当条件,避免无限递归循环

while i <= IND  DO  //while语句的开头,while 判断条件 do
  逻辑内容
end while;    //while语句的结尾

存储过程的递归调用有两个核心:

1、设置树的极限深度(由于mysql数据库的存储过程调用中树的深度默认为0,即不建议存储过程调用存储过程,所以需要这样的设置)

SET @@max_sp_recursion_depth = 100;   //绝大部分情况设置100就够用了,除非递归调用的深度超过100

去掉则会报错:

Recursive limit 0 (as set by the max_sp_recursion_depth variable)

2、调用自己

call test(substring_index(substring_index(ids,',', i), ',', -1));  //call 存储过程名(参数)

最后,由于我的permission表的树形结构的根节点id是0,所以我在生成存储过程后执行的语句为

call test(0)

这样就可以为permision表中的permission_path字段自动赋上路径值

其实存储过程的用法并不复杂,只要记住格式就行了,固定的格式开头和结尾,中间的逻辑都可以是非常简单的语句。而存储过程的递归调用需要注意的地方无非是树的深度的设置,以及防止死循环的逻辑。对于用代码写过递归调用的朋友们来说这不是什么有难度的事,如果没有写过递归调用这样的逻辑,建议先通过代码熟悉递归调用的特点以及注意事项,再来写sql!

ps:第一次写博客,如有不足的地方欢迎指出!

原文:https://www.cnblogs.com/jagerLan/p/9048747.html

其他编程语言递归调用的次数限制

原文:https://blog.csdn.net/losfound/article/details/4647036

递归调用的次数限制 

2009年10月09日 18:49:00 losfound 阅读数:1147

递归调用的次数受到程序堆栈大小的限制,以下代码可以进行测试。

void TestRecur()
{
 int a[1024];    //在栈上分配

 static int count = 0;

 cout << count << " " << flush;
 count++;

 if(count < 1000)
 {
  __try
  {
   TestRecur();
  }
  __except(1)
  {
   cout << "/nerror code: " << _exception_code();
   exit(1);
  }
 }

}

int main()

{

 TestRecur();

}

VisualStudio默认的栈空间是1M,可以更改默认栈空间:

项目-》属性-》配置属性-》链接器-》系统-》堆栈保留大小

原文:https://blog.csdn.net/losfound/article/details/4647036

原文:https://ask.csdn.net/questions/674592?sort=id

运行时出现:已达到最大递归限制

原来Python确实有递归次数限制,默认最大次数为1000

程序默认递归栈最多30层,没事不要用递归,能用迭代就迭代

递归有限制的,会爆栈 ,每一次递归都是向栈里面压,递归层级过多的话就会StackOverflow
解决方法是改为迭代,或者是尾递归优化

递归太深会造成调用栈过长,而虚拟机本身是又大小限制的,建议用循环代替,或者优化递归条件

你这是什么语言?java语言默认栈的大小可以调大(一个虚拟机参数,很好调整),这样递归次数可以变大一点,你可以查查你这个语言调整栈大小如何配置。

原文:https://ask.csdn.net/questions/674592?sort=id

https://bbs.csdn.net/topics/360213526

超出了存储过程、函数、触发器或视图的最大嵌套层数(最大层数为 32)

https://bbs.csdn.net/topics/390471400

C语言的函数有递归次数限制吗? 

https://www.cnblogs.com/wozijisun/p/5642540.html

Python中递归的最大次数

http://www.itpub.net/forum.php?mod=viewthread&tid=1795238

递归语句错误:递归迭代次数太多

http://bbs.chinaunix.net/thread-1006471-1-1.html

递归的最大深度有限制吗?

https://bbs.csdn.net/topics/390308456

如何限制递归函数的次数?

原文:https://blog.csdn.net/fareast_mzh/article/details/82940597

测试 最大递归次数 调用栈大小的限制

2018年10月04日 21:22:25 fareast_mzh 阅读数:119

* stackoverflow.php

 
  1. <?php

  2. function recursiveFn(&$i) {

  3. $i++;

  4. recursiveFn($i);

  5. }

  6.  
  7. try {

  8. $i = 0;

  9. recursiveFn($i);

  10. } catch (LengthException $ex) {

  11. // echo 'i='.$i.' error: ' . $ex;

  12. echo $ex->getMessage();

  13. }

PHP Fatal error:  Uncaught Error: Maximum function nesting level of '256' reached, aborting! 

php最大递归调用 256次

* stackoverflow.js

 
  1. var i = 0;

  2.  
  3. function recursiveFn() {

  4. i += 1;

  5. recursiveFn();

  6. }

  7.  
  8. try {

  9. recursiveFn();

  10. } catch (ex) {

  11. console.log('i = ' + i + ' error: ' + ex);

  12. }

$ node stackoverflow.js

i = 15681 error: RangeError: Maximum call stack size exceeded

node.js 最大递归调用 15681次

i = 15665 error: RangeError: Maximum call stack size exceeded

Chrome 最大递归调用 15665 次

i = 174556 error: InternalError: too much recursion

Firefox 最大递归调用 174556 次

原文:https://blog.csdn.net/fareast_mzh/article/details/82940597

猜你喜欢

转载自blog.csdn.net/xuheng8600/article/details/85334909