MSSQL

[MSSQL] ERROR CODE 666. UNIQUIFIER 고유 식별자 최대값 초과

띠옹떼옹 2024. 8. 22. 09:17
중복 그룹에 대한 시스템 생성 고유 값이 파티션 ID가 %I64d인 인덱스에서 최대값을 초과했습니다. 인덱스 삭제 및 다시 만들기로 이 문제를 해결할 수 있습니다. 그렇지 않으면 다른 클러스터링 키를 사용합니다.

 

고유하지 않은 값을 가진 클러스터형 인덱스로 인해 666 오류가 발생했다.

UNIQUIFIER 값은 INT형으로 2,147,483,647 까지만 값을 가질 수 있는데, 해당 값을 초과하면 666 에러코드가 발생한다.

자세한 내용은 MVP 강성욱 님 블로그 글을 참고하면 좋다.
(https://m.blog.naver.com/sqlmvp/221318954831)

 

고유한 값을 가지는 데이터가 동일한 테이블에 21억건 이상 존재하는 경우에 INSERT하는 케이스만 에러가 발생하는 것으로 알고있었는데 UPDATE 구문에서도 해당 에러가 발생했다.

 

테스트용 테이블을 만들어서 확인해보자.


USE TEST

DROP TABLE IF EXISTS TBL_NON_UNIQUE_CIX

-- 테스트용 테이블 생성
CREATE TABLE TBL_NON_UNIQUE_CIX
(
	ID		BIGINT			NOT NULL IDENTITY(1,1) 
,	[NAME]	NVARCHAR(32)	NOT NULL
	CONSTRAINT PK_TBL_NON_UNIQUE_CIX  PRIMARY KEY NONCLUSTERED (ID) -- 넌클러스터드 PK
)

-- 유니크 속성이 없는 클러스터드 인덱스 생성
CREATE CLUSTERED INDEX NIX_TBL_NON_UNIQUE_CIX_NAME ON TBL_NON_UNIQUE_CIX([NAME])

-- 데이터 INSERT
INSERT INTO TBL_NON_UNIQUE_CIX([NAME])
VALUES (N'TEST')

 

테이블에 생성된 인덱스 정보는 아래와 같다.(EXEC SP_HELPINDEX TBL_NON_UNIQUE_CIX)

 

SP_HELPINDEX

 

인덱스와 페이지 정보를 조회해보자

-- 추적 플래그 ON 처리
DBCC TRACEON(3604)
-- 넌클러스터드 인덱스 정보 확인
DBCC IND('TEST', 'TBL_NON_UNIQUE_CIX', 2)
-- 넌클러스터드 인덱스 페이지 정보 확인
DBCC PAGE('TEST', 1, 113233, 3)

키를 고유하게 만들기 위한 UNIQUIFIER 컬럼이 존재하며, 초기에는 0으로 저장되어있는 것을 확인할 수 있다.

 

현재 상태에서 클러스터드 인덱스로 설정된 컬럼인 NAME 컬럼을 같은 값으로 업데이트하면 어떻게 될까?

UPDATE	DBO.TBL_NON_UNIQUE_CIX
SET		[NAME]	= N'TEST'
WHERE	ID		= 1

DBCC PAGE('TEST', 1, 113233, 3)

1번 실행
8번 실행

같은 값으로 UPDATE하면 UNIQUIFIER 값이 증가하지 않을 줄 알았다.

 

생각해보니 클러스터 인덱스로 설정된 데이터를 UPDATE하면 인덱스 페이지에 새로운 오프셋을 할당해서 저장하고 이전 값은 GHOST_RECORD 처리되어 고스트 프로세스가 돌면서 후에 제거하기 때문에 해당 이슈가 발생하는 것이었다.

 

클러스터 인덱스로 설정된 컬럼을 동일한 값으로 업데이트하는 쿼리가 INT 자료형 범위인 2,147,483,647 를 초과 하는경우 해당 오류가 발생한다.

 

UNIQUIFIER 값은 엔진 내부에서 관장하는 값으로 임의로 수정하거나 자료형을 수정할 수 없다.

 

에러코드 666을 해결하기 위해서는 테이블의 인덱스를 리빌드하거나 삭제 후 재생성하면 조치할 수 있다.

이것은 용량이 적은 테이블에 한해서 이고, 대용량 테이블의 경우 위와 같이 조치하면 기도메타로 울면서 인덱스 리빌드가 완료되길 간절히 바라고 있을 수도 있다. 😱

 

해당 현상이 일어날 확률은 정말 미비하지만... 혹여나 현재 담당하는 장비에 해당케이스와 동일하게 설정되어있는 경우가 있는지 파악해보는 것도 좋을 것 같다.

 

원천적으로 재발을 방지하기 위해서는 클러스터 인덱스를 유니크하게 만들면 된다.

DROP INDEX TBL_NON_UNIQUE_CIX.NIX_TBL_NON_UNIQUE_CIX_NAME
CREATE UNIQUE CLUSTERED INDEX UNIX_TBL_NON_UNIQUE_CIX_NAME ON TBL_NON_UNIQUE_CIX([NAME], ID)

이렇게 생성하고 다시 확인하면

DBCC IND('TEST', 'TBL_NON_UNIQUE_CIX', 2)
DBCC PAGE('TEST', 1, 137497, 3)

유니크 속성을 부여했기 때문에 UNIQUIFIER 컬럼은 생성되지 않는다.

UNIQUE 속성을 별도로 부여하지 않으면 UNIQUIFIER 컬럼은 생성되고 고유한 값이기 때문에 UNIQUIFIER값이 상승되지 않는다.


 

클러스터 인덱스를 생성할 때 UNIQUE 속성을 설정하지 않은 테이블에 대해 인덱스 설정 컬럼에 동일한 값이 INT 자료형 범위 만큼 INSERT되거나, 수정 전 값과 동일하게 UPDATE 되는 경우 UNIQUIFIER 값이 INT 자료형 범위를 초과하게 되어 에러코드 666이 발생하여 장애가 발생할 수 있다.

고유하지 않은 클러스터인덱스를 생성할 때는 위 사항에 주의하며, 데이터가 어떻게 처리되고 있는지 면밀히 파악하여 생성해야한다.