T-SQL 2012,While 循环最大迭代次数?

标签 t-sql crash while-loop sql-server-2012 max

我在 SQL 2012 中遇到了一些在 T-SQL 中带有 WHILE 循环的情况,这是我以前从未见过的,也是我没想到的。经过故障排除后,看来我是正确的,但想确认其他人是否遇到过这个问题,或者他们是否可以复制它。

WHILE 循环的最大迭代次数似乎略多于 1300 万次迭代。我将在下面提供两个代码示例,一个已损坏,另一个可以解决此限制。 (如果你想知道我为什么这样做,我想构建一个“数据仓库”,其中包含半随机选择的数据,稍后可用于测试,这似乎是创建它的最简单路径。因此,这些代码示例只是测试,以确保我能够做到这一点。)

    DATABASE: TESTDB
    TABLE: tbl_A
    COLUMNS:
        a (PK, bigint, not null) --Starts at zero, count upward
        b (bigint, not null) -- Starts at 1 Quadrilion, count downward
        c (bitint, null) -- empty for now

然后我插入一条记录:

    INSERT INTO tbl_A (a, b) VALUES (0, 999999999999999);

然后我运行以下命令,这会导致 VS 2012 在 while 循环中迭代超过 1300 万次后挂起并崩溃:

USE TESTDB
GO
SET NOCOUNT ON;
---------------------------------------------------------------------
DECLARE @countUp bigint = (SELECT max(a)+1 FROM [dbo].[tbl_A]);
DECLARE @countDown bigint = (SELECT min(b)-1 FROM [dbo].[tbl_A]);
---------------------------------------------------------------------
WHILE (@countDown > 0)
BEGIN
    INSERT INTO tbl_A (a, b) VALUES (@countUp, @countDown);
    SET @countUp += 1;
    SET @countDown -= 1;

    IF ((@countDown % 1000000) = 0)
        PRINT char(9) + char(9) + char(9) + char(9) + CAST(@loop AS VARCHAR) + ': ' + CAST(@countDown AS VARCHAR) + '  <--- (' + CONVERT(varchar, GETDATE(), 120) + ')';
    ELSE IF ((@countDown % 200000) = 0)
        PRINT CAST(@loop AS VARCHAR) + ': ' + CAST(@countDown AS VARCHAR);
END
---------------------------------------------------------------------
SET NOCOUNT OFF;

然而,当我强制上述代码在 1300 万处停止 WHILE 循环时,它永远不会达到挂起的地步,然后围绕该循环创建一个 WHILE 循环,而 @countDown > 0 时,它似乎会继续数据库中运行良好,远远超过 13+ 百万个事务...现在仍在以近 2600 万个事务运行...并且仍在继续...

SET NOCOUNT ON;
---------------------------------------------------------------------
DECLARE @loop int = 1;
DECLARE @countUp bigint = (SELECT max(a)+1 FROM [dbo].[tbl_A]);
DECLARE @countDown bigint = (SELECT min(b)-1 FROM [dbo].[tbl_A]);
DECLARE @StopValue bigint;
    IF (@countDown > 13000000)
        SET @StopValue = @countDown - 13000000;
    ELSE
        SET @StopValue = 0;

WHILE (@countDown > 0)
BEGIN
        ---------------------------------------------------------------------
        WHILE (@countDown <> @StopValue)
        BEGIN
            INSERT INTO tbl_A (a, b) VALUES (@countUp, @countDown);
            SET @countUp += 1;
            SET @countDown -= 1;

            IF ((@countDown % 1000000) = 0)
                PRINT char(9) + char(9) + char(9) + char(9) + CAST(@loop AS VARCHAR) + ': ' + CAST(@countDown AS VARCHAR) + '  <--- (' + CONVERT(varchar, GETDATE(), 120) + ')';
            ELSE IF ((@countDown % 200000) = 0)
                PRINT CAST(@loop AS VARCHAR) + ': ' + CAST(@countDown AS VARCHAR);
        END
        ---------------------------------------------------------------------
        SET @loop += 1;
        SELECT @countUp=(max(a)+1) FROM [dbo].[tbl_A];
        SELECT @countDown=(min(b)-1) FROM [dbo].[tbl_A];
        IF (@countDown > 13000000)
            SET @StopValue = @countDown - 13000000;
        ELSE
            SET @StopValue = 0;
        ---------------------------------------------------------------------
END

SET NOCOUNT OFF;

还有人遇到过这种情况吗?或者说,你能复制它吗?我想知道这是否是我的 VS 2012 中的某些设置、MS 在 WHILE 循环上放置的一般最大设置,或者是我的系统特定的某些设置...

看来我的系统也有足够的磁盘空间和电量。所以我怀疑这会对这个限制产生任何影响。

    Windows 7 Ultimate 64bit
    SQL Server 2012 Dev. Ed. 64bit
    6-core 3.47 GHz (12-way with hyper threading)
    24 GB DDR3-1600 Memory
    OS on SSD (3 Gbps SATA II)
    DB is on two SSD drives in RAID 0 config (on 6 Gbps SATA III)

很想得到反馈。 (抱歉这么长的帖子。)

最佳答案

如果我们的循环条件是“数字等于或大于数字”,那么,T-SQL number types我们可以选择BIGINT类型进行测试。

因为以下语句:

DECLARE @LoopLimit  BIGINT = 9223372036854775807
SET @LoopLimit = @LoopLimit + 1 
GO

DECLARE @LoopLimit  BIGINT = -9223372036854775808
SET @LoopLimit = @LoopLimit - 1
GO

生成:

Msg 8115, Level 16, State 2, Line 3 Arithmetic overflow error converting expression to data type bigint.

我猜最大的迭代周期如下:

SET NOCOUNT ON
GO

    DECLARE @LoopLimit  BIGINT = 9223372036854775807

    WHILE @LoopLimit <> -9223372036854775808
    BEGIN
        SET @LoopLimit = @LoopLimit - 1
    END

SET NOCOUNT OFF
GO

不幸的是,我正在工作,无法等待整个查询执行(我可能会在 sleep 前在家运行它),但我有以下查询来检查是否有 1300 万次迭代通过:

SET NOCOUNT ON
GO

    DECLARE @LoopLimit  BIGINT = 9223372036854775807
    DECLARE @MilionsCounter BIGINT = 0

    WHILE @LoopLimit <> -9223372036854775808
    BEGIN
        SET @LoopLimit = @LoopLimit - 1
        SET @MilionsCounter = @MilionsCounter + 1
        IF @MilionsCounter % 1000000 = 0 PRINT @MilionsCounter / 1000000
    END

SET NOCOUNT OFF
GO

enter image description here

所以,它仍在运行。大家可以自己查一下,没有1300万的限制(在SQL Management Studio 2012上测试)。

关于T-SQL 2012,While 循环最大迭代次数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18608091/

相关文章:

sql-server - SQL Server 2019跨数据库函数调用权限

iPhone 应用程序运行了数百次,然后在启动时因内存错误而崩溃,然后直到重新启动才运行 - 为什么?

c - 循环永远持续

memory - 当 eden 空间为 100% 时,JVM 崩溃

linux - 哪个进程正在发送SIGKILL

java - 用户输入仅发生一次或在循环期间永不停止

python - 用列表理解替换 while 循环

sql-server - SQL Server 2005 - 使用前导零格式化十进制数(包括带符号的小数!)

sql-server - 真正的空安全比较

sql-server - 基于JOIN和聚合条件的SQL DELETE