2016-10-30 6 views
1

このテーブルには4000万の行があり、クエリには永遠にかかる以外は、以下のようなalterコマンドを実行しようとしています。デフォルト値の何百万行のテーブルを変更

ALTER TABLE [dbo].[ConsumerProduct] 
ADD IsPendDefault [bit] NOT NULL DEFAULT ((0)) 
GO 

そこで私は5000の、それが戻ってnullではないに変更するよりも、バッチ40万行のためのすべての列を更新するよりも、nullを変えることを考えました。この

ALTER TABLE [dbo].ConsumerProduct 
ADD IsPendDefault [bit] NULL 
GO 

SET ROWCOUNT 10000 

WHILE (1=1) 
BEGIN 
    BEGIN TRANSACTION 

    UPDATE ConsumerProduct 
    SET IsPendDefault = 0 
    WHERE IsPendDefault IS NULL 

    -- Update 1000 nonupdated rows 
    IF @@ROWCOUNT = 0 
    BEGIN 
     COMMIT TRANSACTION 
     BREAK 
    END 

    COMMIT TRANSACTION 
END 

ALTER TABLE [dbo].ConsumerProduct 
ALTER COLUMN IsPendDefault [bit] NOT NULL 
GO 

でも、このようなクエリ

何かが永遠にかかります。列内のデフォルト値を使用してテーブルを変更する方が簡単に簡単ですか?

私は、SQL ServerのEnterpriseエディションではSQL Serverの2012

+0

私はupdate where節でプライマリキーを使用し、バッチで更新します。私は、各バッチを独立したステートメントにし、ループに頼ることはありません。次の100,000種類のステートメントを入手してください。 –

答えて

2

を使用しています2012

ALTER TABLE [dbo].[ConsumerProduct] 
ADD IsPendDefault [bit] NOT NULL DEFAULT ((0)) 

an online operationです。だから私はあなたがEEにいないと仮定します。

実際にすべての列の値を0に更新する必要がありますか?

1つのオプションは、ちょうど列がNULL

ALTER TABLE [dbo].ConsumerProduct 
ADD IsPendDefault [bit] NULL 

にNULL可能で、デフォルトであることと、コードがfalseとしてNULLを扱うことを確認することができるようになります。例えばSELECT ISNULL(IsPendDefault,0) AS IsPendDefaultとなります。

NOT NULLに変更したい場合は、バッチを分割して更新するのが最適です。しかし、以前のバッチですでに更新された行をスキャンすることなく、各更新が更新する行のバッチをすばやく見つけることができるようにする必要があります。

(整数IDのプライマリキーを使用している場合)オプションは、希望のバッチサイズの範囲に単純に分割して、各バッチを目的の範囲にシークさせることです。

DECLARE @I   INT = 0, 
     @BatchSize INT = 5000; 

WHILE @I <= (SELECT MAX(ID) 
      FROM ConsumerProduct) 
    BEGIN 
     UPDATE ConsumerProduct 
     SET IsPendDefault = 0 
     WHERE IsPendDefault IS NULL 
      AND ID >= @I 
      AND ID < @I + @BatchSize; 

     SET @I = @I + @BatchSize; 
    END 

大規模な範囲が空であるか、まれにばらつきがある場合は、より綿密にアプローチする価値があります。

CREATE TABLE #processed 
    (
    ID INT PRIMARY KEY 
) 

DECLARE @ID  INT = 0, 
     @BatchSize INT = 5000; 

WHILE 1 = 1 
    BEGIN 
     WITH T 
      AS (SELECT TOP (@BatchSize) * 
       FROM ConsumerProduct 
       WHERE ID > @ID 
         AND IsPendDefault IS NULL 
       ORDER BY ID) 
     UPDATE T 
     SET IsPendDefault = 0 
     OUTPUT inserted.ID 
     INTO #processed; 

     IF @@ROWCOUNT < @BatchSize 
     BREAK; 

     SELECT @ID = MAX(ID) 
     FROM #processed; 

     TRUNCATE TABLE #processed 
    END 

DROP TABLE #processed 
+0

あなたは絶対に正しいです。残念なことに、それをnullにすることは、コード変更を必要とするためオプションではありません。あなたは心に留めているバッチ処理のためのpsedoコードを持っていますか?私はrowcountを使って自分のバージョンのバッチ処理を試みましたが、それは私がそこに持っている解決策よりも悪い結果でした。 – prapoerfft

+0

@prapoerfft - 整数のクラスタ化プライマリキーがありますか? –

+0

はいID列があります。タイプがCLUSTEREDのテーブルにあるプライマリキー – prapoerfft

関連する問題