2016-10-30 5 views
1

이 테이블에는 4 천만 개의 행이 있고 쿼리에는 영원히 걸리는 점을 제외하고 아래와 같이 alter 명령을 실행하려고합니다. 수백만 개의 행이 기본값으로 설정된 테이블 변경

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

는 그러므로 나는 5000의 일괄 40000000 행에 대한 모든 열을 갱신하지 않고,이 null로 변경하고 생각하고보다 것은 다시 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 서버의 엔터프라이즈 버전에서 SQL 서버 2012

+0

나는 update where 절에서 기본 키를 사용하고 일괄 처리로 업데이트합니다. 각 일괄 처리를 독립 실행 형 구문으로 만들고 루프에 의존하지 않을 것입니다. 다음 10 만 가지 범위의 성명을 얻으십시오. –

답변

2

을 사용하고 2012

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

an online operation입니다. 그래서 나는 당신이 EE에 없다고 생각합니다.

실제로 모든 열 값을 0으로 업데이트해야합니까?

하나의 옵션은 열이 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

관련 문제