AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 156164
Accepted
Bogdan Bogdanov
Bogdan Bogdanov
Asked: 2016-11-24 05:52:45 +0800 CST2016-11-24 05:52:45 +0800 CST 2016-11-24 05:52:45 +0800 CST

可以参与 SET 操作的局部变量的最大数量是多少?

  • 772

我有一个包含业务逻辑的存储过程。在它里面我有大约 1609 个变量(不要问我为什么,这就是引擎的工作原理)。我尝试将SET一个变量连接到所有其他变量的连接值。结果在创建过程中出现错误:

消息 8631,级别 17,状态 1,过程 XXX,行 YYY 内部错误:已达到服务器堆栈限制。请在您的查询中寻找潜在的深层嵌套,并尝试简化它。

我发现错误是由于我需要在SET操作中使用的变量数量造成的。我可以通过将其分成两部分来执行任务。

我的问题是这方面有一些限制吗?我查了,但没有找到。

我们检查了此 KB中描述的错误,但这不是我们的情况。我们在代码中不使用任何CASE表达式。我们使用该临时变量来准备必须使用 CLR 函数替换的值列表。我们将 SQL Server 更新到 SP3 CU6(最新),但我们仍然遇到错误。

sql-server sql-server-2012
  • 4 4 个回答
  • 3389 Views

4 个回答

  • Voted
  1. Best Answer
    Paul White
    2017-02-28T04:28:50+08:002017-02-28T04:28:50+08:00

    消息 8631,级别 17,状态 1,第 xxx 行
    内部错误:已达到服务器堆栈限制。
    请在您的查询中寻找潜在的深层嵌套,并尝试简化它。

    由于 SQL Server 解析和绑定此类语句的方式(作为两个输入串联的嵌套列表),长SET或变量赋值串联列表会发生此错误。SELECT

    例如,SET @V = @W + @X + @Y + @Z被绑定到如下形式的树中:

    ScaOp_Arithmetic x_aopAdd
        ScaOp_Arithmetic x_aopAdd
            ScaOp_Arithmetic x_aopAdd
                ScaOp_Identifier @W 
                ScaOp_Identifier @X 
            ScaOp_Identifier @Y 
        ScaOp_Identifier @Z 
    

    前两个元素之后的每个连接元素都会在此表示中产生额外的嵌套级别。

    SQL Server 可用的堆栈空间量决定了此嵌套的最终限制。当超出限制时,会在内部引发异常,最终导致如上所示的错误消息。抛出错误时的示例进程调用堆栈如下所示:

    堆栈跟踪

    复制品

    DECLARE @SQL varchar(max);
    
    SET @SQL = '
        DECLARE @S integer, @A integer = 1; 
        SET @S = @A'; -- Change to SELECT if you like
    
    SET @SQL += REPLICATE(CONVERT(varchar(max), ' + @A'), 3410) +';'; -- Change the number 3410
    
    -- SET @S = @A + @A + @A...
    EXECUTE (@SQL);
    

    由于内部处理多个串联的方式,这是一个基本限制。它同样影响SET和SELECT变量赋值语句。

    解决方法是限制在单个语句中执行的连接数。这通常也会更有效,因为编译深度查询树是资源密集型的。

    • 16
  2. Solomon Rutzky
    2018-01-01T11:20:50+08:002018-01-01T11:20:50+08:00

    受@Paul回答的启发,我做了一些研究,发现虽然堆栈空间确实限制了连接的数量,而且堆栈空间是可用内存的函数,因此会有所不同,但以下两点也是正确的:

    1. 有一种方法可以将额外的连接填充到单个语句中,并且
    2. 使用这种方法超越初始堆栈空间限制,可以找到一个实际的逻辑限制(看起来没有变化)

    首先,我修改了 Paul 的测试代码来连接字符串:

    DECLARE @SQL NVARCHAR(MAX);
    
    SET @SQL = N'
        DECLARE @S VARCHAR(MAX), @A VARCHAR(MAX) = ''a''; 
        SET @S = @A';
    
    SET @SQL += REPLICATE(CONVERT(NVARCHAR(MAX), N' + @A'), 3312) + N';';
    
    -- SET @S = @A + @A + @A...
    SET @SQL += N'SELECT DATALENGTH(@S) AS [Chars In @S];';
    EXECUTE (@SQL);
    

    通过这个测试,我在不太好的笔记本电脑(只有 6 GB 的 RAM)上运行时可以获得的最高值是:

    • 3311(返回 3312 个总字符)使用 SQL Server 2017 Express Edition LocalDB (14.0.3006)
    • 3512(返回 3513 个总字符)使用 SQL Server 2012 Developer Edition SP4 (KB4018073) (11.0.7001)

    在收到错误8631之前。

    接下来,我尝试使用括号对串联进行分组,以便该操作将串联多组串联。例如:

    SET @S = (@A + @A + @A + @A) + (@A + @A + @A + @A) + (@A + @A + @A + @A);
    

    这样做我能够远远超出之前 3312 和 3513 变量的限制。更新后的代码是:

    DECLARE @SQL VARCHAR(MAX), @Chunk VARCHAR(MAX);
    
    SET @SQL = '
        DECLARE @S VARCHAR(MAX), @A VARCHAR(MAX) = ''a''; 
        SET @S = (@A+@A)';
    
    SET @Chunk = ' + (@A' + REPLICATE(CONVERT(VARCHAR(MAX), '+@A'), 42) + ')';
    
    SET @SQL += REPLICATE(CONVERT(VARCHAR(MAX), @Chunk), 762) + ';';
    
    SET @SQL += 'SELECT DATALENGTH(@S) AS [Chars In @S];';
    
    -- PRINT @SQL; -- for debug
    
    -- SET @S = (@A+@A) + (@A + @A...) + ...
    EXECUTE (@SQL);
    

    最大值(对我来说)现在42用于第一个REPLICATE,因此每组使用 43 个变量,然后762用于第二个REPLICATE,因此使用 762 组,每组 43 个变量。初始组使用两个变量进行硬编码。

    @S现在的输出显示变量中有 32,768 个字符。如果我将初始组更新为(@A+@A+@A)而不是 just (@A+@A),则会收到以下错误:

    消息 8632,级别 17,状态 2,行 XXXXX
    内部错误:已达到表达式服务限制。请在您的查询中寻找可能复杂的表达式,并尝试简化它们。

    请注意,错误编号与以前不同。现在是:8632。而且,无论我使用 SQL Server 2012 实例还是 SQL Server 2017 实例,我都有同样的限制。

    这里的上限——32,768——是(在 .NET 中)IF的最大容量(最大值为 32,767,但许多/大多数编程语言中的数组是从 0 开始的),这可能并非巧合。SMALLINTInt160

    • 5
  3. MarmiK
    2017-02-08T04:02:43+08:002017-02-08T04:02:43+08:00

    现在,这只是内存不足,换句话说,因为存储过程的操作在内存中完成,并且 SQL 可用的可用硬件晶体管或虚拟页面内存已满!

    所以它基本上是 SQL Server 中的 Stack Overflow。

    现在,首先尝试简化流程,因为我们知道您需要 1609 个变量,

    但是您是否同时需要所有变量?

    我们可以在需要的地方声明和使用变量。

    例如:

    Declare @var1 int, @Var2 int @Var3 int, .... , @var1000 int; -- Here assume Thousand Variables are declared
    
    Declare @Tot Int;
    SET @Tot = 0;
    if(True)
    Begin
        SET @TOT = @TOT+ VAR1 + VAR2 + .... + VAR1000; -- This might fail; 
    End
    

    但是如果我们通过添加来循环尝试这个

    Declare @Tot Int;
    SET @Tot = 0;
    DECLARE @i int, @Count int;
    SET @i = 1;
    SET @Count = 1609;
    WHILE (@i <= @Count)
    BEGIN
       DECLARE @SQL NVARCHAR(128);
       SET @SQL = 'SET @TOT = @TOT+ VAR'+ cast(@i as nvarchar);
       EXEC (@SQL);
       SET @i = @i + 1;
    END
    

    注意:这将使用更多的 CPU,并且需要更多的计算时间。

    现在这会很慢,但具有更少的内存使用量的优势。

    我希望这会有所帮助,请发布您的查询,以便我们了解确切的情况。

    • 0
  4. Matthew Sontum
    2017-02-13T15:25:44+08:002017-02-13T15:25:44+08:00

    使用 SELECT 语句而不是 SET 可以提高性能和可读性,并且可以让您绕过所述错误。所以而不是:

    SET @a = 1
    SET @b = 2
    SET @c = @e + 2*@d
    

    你可以做:

    SELECT @a = 1, @b = 2, @c = @e + 2 * @d
    

    并在一个语句中设置所有三个值。

    • -4

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve