我在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;
然而,当我强制上面的代码停止WHILE循环为1300万时,所以它永远不会到达悬挂点,然后围绕那个创建一个WHILE循环,而@countDown&gt; 0,它似乎继续在数据库中超过1300多万笔交易运行良好...它现在仍在运行近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)
对反馈感到好奇。 (抱歉这么长的帖子。)
答案 0 :(得分:1)
如果我们的循环条件是“数字等于或大于数字”,那么,我们可以选择<{3>}, 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算术溢出错误 将表达式转换为数据类型bigint。
我猜最大的迭代周期类似于以下内容:
SET NOCOUNT ON
GO
DECLARE @LoopLimit BIGINT = 9223372036854775807
WHILE @LoopLimit <> -9223372036854775808
BEGIN
SET @LoopLimit = @LoopLimit - 1
END
SET NOCOUNT OFF
GO
不幸的是,我在工作,我无法等待整个查询被执行(我可能会在睡觉前在家里运行),但我有以下查询来检查是否有13百万次迭代通过:
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
所以,它仍然在运行。您可以自己检查一下,没有1300万的限制(在SQL Management Studio 2012上测试过)。