2

SQL 2012 で、T-SQL の WHILE ループで、これまでに見たことのない、予期しないものに遭遇しました。トラブルシューティング後、私は正しいように見えますが、他の誰かがこれに出くわしたかどうか、または複製できるかどうかを確認したかったのです.

WHILE ループの最大反復回数は 1,300 万回を少し超えるようです。以下に 2 つのコード サンプルを示します。1 つは壊れたもので、もう 1 つはこの制限を回避したものです。(なぜ私がそうしているのか知りたいのであれば、後でテストに使用できる半ランダムなデータを選択した「データ ウェアハウス」を構築したいと思います。これが最も簡単な方法のように思えます。したがって、これらのコード サンプルは、それができるかどうかを確認するための単なるテストです。)

    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

次に、1 つのレコードを挿入します。

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

次に、次のコマンドを実行すると、while ループで 1,300 万回を少し超える繰り返しの後で VS 2012 がハングしてクラッシュします。

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 ループを 1,300 万で停止させると、ハングすることはなく、その周りに WHILE ループを作成すると、@countDown > 0 の間、正常に実行され続けるようですDB での 1,300 万以上のトランザクションを超えて...現在も約 2,600 万で実行されています...そしてまだ続いています...

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)

フィードバックに興味があります。(このような長い投稿で申し訳ありません。)

4

1 に答える 1

2

ループ条件が「数値以上の数値」である場合、選択できるT-SQL 数値型、テスト用のBIGINT型があります。

次のステートメントのため:

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

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

生成:

メッセージ 8115、レベル 16、状態 2、行 3 式をデータ型 bigint に変換中に算術オーバーフロー エラーが発生しました。

最大の反復サイクルは次のようなものだと思います。

SET NOCOUNT ON
GO

    DECLARE @LoopLimit  BIGINT = 9223372036854775807

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

SET NOCOUNT OFF
GO

残念ながら、私は仕事をしていて、クエリ全体が実行されるのを待つことができません (就寝前に自宅で実行する可能性があります) が、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

ここに画像の説明を入力

だから、それはまだ実行されています。1,300 万の制限がないことを自分で確認できます (SQL Management Studio 2012 でテスト済み)。

于 2013-09-04T10:16:40.970 に答える