2009-07-20 3 views
10

약 4 백만 개의 레코드가있는 테이블의 필드를 변경하려고합니다. 나는 이러한 필드의 모든 값이 NULL NOT하고SQL Server ALTER 필드 NOT NULL이 오래 걸림

ALTER TABLE dbo.MyTable 
ALTER COLUMN myColumn int NOT NULL 

에 NULL NOT이 필드를 변경하려는 것을 보장 ...이 업데이트를 수행하는 영원히 걸릴 것으로 보인다. 속도를 높이는 방법이나 아니면 영업 시간 외에는 밤새도록 하던가?

또한 테이블 잠금이 발생할 수 있습니까?

+1

개인적으로 오프 피크 시간을 제외한 모든 시간에 기존의 대형 테이블에서 테이블 구조를 변경하지 않을 것입니다.비록 그것이 매우 빠르다 고해도, 사용자가 변화를 일으켜 문제를 일으키는 순간에 일을하는 과정에서 사용자를 유발할 수 있습니다. 큰 변경 사항은 단일 사용자 모드에서도 가장 잘 수행됩니다. 사용자가 아무 것도 할 수없는 예약 된 유지 보수 기간 (예 : 물론 피크 시간대가 아닌 시간에 발표 됨)을 사용하면 오류가 발생하는 무언가를하는 도중에 불행한 사용자를 갖는 것보다 훨씬 더 좋습니다. – HLGEM

+0

변경할 열이 FK 제약 조건에 포함되어 있습니까? – onupdatecascade

+1

프로파일 러의 빠른 테스트에서 테이블에 대한 Sch-M 잠금 (기본적으로 모든 것과 호환되지 않음) (http://msdn.microsoft.com/en-us/library/ms186396.aspx). 그런 다음 모든 페이지를 읽고 모든 행이 유효한지 확인해야합니다. –

답변

4

필드를 변경하지 않고 필드를 변경하고 null이 아닌 값으로 만들 수 있습니다. 정말로 시간이 없다면 필드에 제약 조건을 추가하여 필드가 null이 아닌지 확인하십시오. 이렇게하면 check with no 옵션을 사용하고 4 백만 행의 각각을 확인하여 업데이트 여부를 확인할 수 없습니다.

  1. 업데이트되는 새로운 행을 방지하고 변경되지 않은 원래의 사람을 떠나 제약 조건을 사용하여

    CREATE TABLE Test 
    (
        T0 INT Not NULL, 
        T1 INT NUll 
    ) 
    
    INSERT INTO Test VALUES(1, NULL) -- Works! 
    
    ALTER TABLE Test 
        WITH NOCHECK 
         ADD CONSTRAINT N_null_test CHECK (T1 IS NOT NULL) 
    
        ALTER COLUMN T1 int NOT NULL 
    
    INSERT INTO Test VALUES(1, NULL) -- Doesn't work now! 
    

    정말 두 가지 옵션 (추가 편집을 참조하십시오 세 번째)가 있습니다.

  2. null 인 행을 다른 것으로 업데이트 한 후 not null alter 옵션을 적용하십시오. 프로세스가 테이블에서 잠기는 것을 신경 쓰지 않는 한,이 작업은 근무 시간 외에서 실행해야합니다.

특정 시나리오에 따라 두 옵션 중 어느 것이 더 좋을지도 모릅니다. 비록 당신이 떨어져 시간에 그것을 실행해야하기 때문에 옵션을 선택하지 않을 것이다. 장기적으로 당신이 한밤중에 업데이트하는 데 소비하는 시간은 두시간을 절약하기 위해 지름길로 얼굴을 마주보고 있을지 모르는 두통과 비교하면 잘 될 것입니다.

이 모든 것이 언급되었으므로 옵션 2로 가면 근무 시간 외의 작업량을 최소화 할 수 있습니다. 당신이 열을 변경하기 전에에 null가 아닌 행을 업데이트 확인해야하기 때문에, 당신은 천천히 (상대 한 번에 모든 일에)

  1. 보고 각 행
  2. 확인을 통해 이동 커서를 쓸 수 있습니다 그것이 null 인 경우
  3. 적절히 업데이트하십시오. 이 작업은 시간이 걸리지 만 다른 프로그램이 테이블 블록 전체에 액세스하는 것을 잠그지는 않습니다. 합니다 (with(rowlock) 테이블 힌트를 잊지 마세요!)

편집 : 당신은 적절한 열이있는 새 테이블을 만든 다음 원래 테이블에서 데이터를 내보낼 수 있습니다 : 난 그냥 세 번째 옵션의 생각 새로운 것에. 이 작업이 완료되면 원래 테이블을 삭제하고 새 테이블의 이름을 이전 테이블로 변경할 수 있습니다. 이렇게하려면 원본에 대한 종속성을 해제하고 작업이 끝나면 새 프로젝트에 대한 종속성을 설정해야하지만,이 프로세스를 사용하면 업무 외 시간에 수행해야하는 작업량이 크게 줄어 듭니다. 이는 관리 스튜디오를 통해 테이블에 열 순서 변경을 수행 할 때 SQL Server가 사용하는 것과 동일한 접근 방식입니다. 이 접근법에 대해, 나는 청크로 삽입을 수행하여 시스템에 실행 취소 스트레스가 발생하지 않도록하고 다른 사용자가 시스템에 액세스하는 것을 막지 않도록하십시오. 그런 다음 근무 시간 외의 시간에 원본을 삭제하고 두 번째 이름을 변경하고 종속성 등을 적용 할 수 있습니다. 아직 근무 시간이 다소 남아 있지만 다른 접근 방식과 비교하면 아주 적습니다.

sp_rename으로 링크하십시오.

+4

NO CHECK를 사용하면 제한 조건이 신뢰되지 않고 쿼리 최적화 프로그램에서 사용할 수 없습니다. http://sqlblog.com/blogs/tibor_karaszi/archive/2008/01/12/non-trusted-constraints-and-performance.aspx –

+3

또한 NOCHECK 키워드는 NULL/NOT NULL에 적용되지 않습니다.를 참조하십시오. CONSTRAINT 절의 일부인 제한 조건에만 적용됩니다. –

+0

질문에서 OP는 이미 열에 "NULL"값이 없으므로 응답의 두 번째 부분의 관련성을 확신하지 못했습니다. –

2

낙담 죄송하지만 :

  • 을 속도를 어떤 방법 : 아니, 당신은 테이블 구조 자체
  • 을 변경하려면 또는 난 그냥 오프 동안 밤새 그 일을 붙어 있지 않은 경우를 시간? 예, 그리고 그게 아마도 최선의 방법입니다. @HLGEM이 지적했듯이
  • 또한 테이블 잠금이 발생할 수 있습니까? - 동등한 질문에 포럼에서 http://beyondrelational.com/blogs/sankarreddy/archive/2011/04/05/is-alter-table-alter-column-not-null-to-null-always-expensive.aspx

    그리고 마지막으로 고대 역사 :이 주제에 대한 직접 (그것에 대해 NULL을 NULL NOT에서 무슨 일 때문에) 귀하와 관련,하지만 흥미로운 읽을 예

@Kevin 위의 제안으로 2005 년 같은 제안을 하였다 - 제작하는 것은 아니고 제약 조건을 사용하여 열 자체가 아닌 널 (NULL) : http://www.sqlteam.com/Forums/topic.asp?TOPIC_ID=50671

4

유일한 방법은 할이 "신속하게"(*) 내가 아는 그

입니다
  • 소스 테이블에 트리거를 추가하여 필요한 삽입/업데이트/삭제 작업을 섀도우 테이블에 복사 할 수 있도록 필요한 레이아웃이있는 '섀도'테이블을 만듭니다 (팝업이 될 수있는 NULL을 잡으십시오!)
  • 모든 데이터를 소스에서 섀도우 테이블로 복사하십시오 (잠재적으로 작은 덩어리로 작성) (트리거로 이미 복사 한 데이터를 처리 할 수 ​​있는지 확인하고 데이터가 새 구조에 맞는지 확인하십시오 (ISNULL (?))에서/
  • 모든 작업이 완료
  • 는, 명시 적 트랜잭션 내에서 다음을 수행 다른 테이블에
  • 스크립트 밖으로 모든 종속성!
    • (예 접미사 _OLD)
    • 뭔가 다른 소스 테이블의 이름을 변경 소스 테이블
    • 에 종속성을 드롭 스크립트를 실행 shadowtable
    • 에 독점 테이블 소스 테이블에 잠금 및 하나를 얻을 소스 테이블의 원래 이름에 그림자 테이블의 이름을 변경
    • 당신은 거래 (a)의 외부의 마지막 단계를 수행 할 수 있습니다 다시

모든 종속성을 작성하는 스크립트를 실행 이 테이블을 참조하는 테이블의 크기와 크기에 따라 상당히 많은 시간이 걸릴 수 있습니다. 첫 단계는 전혀 시간이 걸리지 않을 것입니다.

언제나 그렇듯이 테스트에서는 테스트를 실행하는 것이 가장 좋습니다 -server first =)

추 신 : NOCHECK를 사용하여 FK를 다시 만들려고하지 마십시오. 옵티마이 저가 쿼리 플랜을 만들 때 고려하지도 않고 고려하지 않으므로 렌더링이 효과가 없습니다.

(* : 신속하게 내려 오는 곳 : 최소한의 다운 타임)

+0

나는 지난 주 동안이 아이디어를 가지고 놀았지만 서로에 대해 알지 못하는 여러 컬럼 변경이있을 수 있으므로 특정 상황에서 문제점을 발견했다. 따라서 "대신"트리거를 동적으로 생성하는 것은 불가능할 것이다. 이것은 모두 자동화되어야 함). 오늘 아침에 그것이 테이블 구동이 될 수 있다는 생각이 들었습니다. 그리고 저는 여러분이 저를 이길 수 있다는 것을 알기 위해 여기에 답을 게시 할 것입니다 :) –

관련 문제