SQL Server 데이터베이스에서 ID 증가가 점프합니다.


126

FeeSQL Server 2012 데이터베이스 ID 증가의 "ReceiptNo"열에 있는 내 테이블 중 하나 에서 갑자기 다음 두 가지 사항에 따라 1이 아닌 100으로 점프하기 시작했습니다.

  1. 1205446이면 1206306으로 점프하고 1206321이면 1207306으로 점프하고 1207314이면 1208306으로 점프합니다. 제가 주목하고 싶은 것은 마지막 세 자리가 일정하게 유지된다는 것입니다. 즉, 점프 할 때마다 306 다음 그림과 같이 발생합니다.

  2. 이 문제는 컴퓨터를 다시 시작할 때 발생합니다.

여기에 이미지 설명 입력


order by ReceiptNo쿼리에 추가 하면 해당 레코드가 실제로 존재하지 않습니까? 레코드를 삽입 할 때 오류가 없는지 확실합니까? 레코드가 삽입을 시도하고 실패하면 ID가 증가하고 레코드가 삭제되는 경우에도 마찬가지입니다. 레코드가 삭제되면 ReceiptNo재설정되지 않습니다. 테이블에 대한 Fee테이블 생성을 게시 할 수 있습니까 ?
Taryn

4
첫 번째 질문은-왜 중요합니까? 임의의 고유 ID 여야합니다.
Andrew

1
이것이 서버에서 실행되고 있습니까 아니면 데스크탑에서 표현됩니까? 서비스가 자주 다시 시작되는 이유가 궁금하십니까?
Martin Smith

@bluefeet 오류가 발생하면 ID가 증가합니다. 오류가 없다고 100 % 확신합니다. 행을 삽입하는 데 사용하는 테이블과 저장 프로 시저를 추가하여 내 질문을 편집합니다.
kashif

@kashif-99 % 확실하지 않습니다. (가) 정확히 1,000 점프 ( 1206306, 1207306, 1207806) 연결 항목 스레드의 설명이 거의 확실 적용을 의미합니다.
Martin Smith

답변:


158

SQL Server 2012 이후 성능 향상으로 인해이 동작이 발생합니다.

할당 할 때 기본적으로 그것은 1000의 캐시 크기를 사용 IDENTITY값을 int열과 서비스가 사용되지 않는 값을 "잃을"수 다시 시작 (캐시 크기는 10,000입니다 bigint/ numeric).

이것은 문서에 언급되어 있습니다.

SQL Server는 성능상의 이유로 ID 값을 캐시 할 수 있으며 데이터베이스 오류 또는 서버 다시 시작 중에 할당 된 값 중 일부가 손실 될 수 있습니다. 이로 인해 삽입시 ID 값에 간격이 생길 수 있습니다. 간격이 허용되지 않는 경우 애플리케이션은 자체 메커니즘을 사용하여 키 값을 생성해야합니다. NOCACHE옵션 과 함께 시퀀스 생성기를 사용하면 커밋되지 않은 트랜잭션에 대한 간격을 제한 할 수 있습니다.

보여준 데이터에서 12 월 22 일 데이터 입력 후 SQL Server를 다시 시작했을 때 값을 예약 한 것 같습니다 1206306 - 1207305. 12 월 24 일부터 25 일까지의 데이터 입력이 다시 시작된 후 SQL Server 1207306 - 1208305는 28 일의 항목에 표시 되는 다음 범위를 예약했습니다 .

비정상적인 빈도로 서비스를 다시 시작하지 않는 한 "손실 된"값은 데이터 유형에서 허용하는 값 ​​범위에 큰 흠집을 만들 가능성이 없으므로 최상의 정책은 이에 대해 걱정하지 않는 것입니다.

이것이 어떤 이유로 실제 문제라면 가능한 해결 방법은 다음과 같습니다.

  1. 당신은을 사용할 수 있습니다 SEQUENCE대신 ID 열이의 예와 사용을위한 작은 캐시 크기를 정의NEXT VALUE FOR 열 기본에.
  2. 또는 추적 플래그 272를 적용하여 IDENTITY 2008 R2까지 버전에서 할당을 기록 . 이는 모든 데이터베이스에 전역 적으로 적용됩니다.
  3. 또는 최신 버전의 경우 실행 ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF하여 특정 데이터베이스에 대한 ID 캐싱을 비활성화합니다.

이러한 해결 방법 중 어떤 것도 간격이 없다는 것을 알고 있어야합니다. 이것은 IDENTITY테이블에 대한 삽입을 직렬화해야만 가능하기 때문에 결코 보장되지 않았습니다 . 틈이없는 컬럼이 필요한 경우 IDENTITY또는 둘 중 하나 와 다른 솔루션을 사용해야합니다.SEQUENCE


1
당신이 말한 것을 확인하기 위해 몇 가지 값을 삽입하고 1208309, 1208310을 얻은 다음 서버를 다시 시작한 다음 행을 추가했을 때 1209309를 얻었습니다. 감사합니다. 이제이 문제를 어떻게 해결할 수 있는지 알려주세요. 이전에 사용했던 2012 대신 SQL Server 2008을 사용하거나 2012를 사용하는 것이 좋습니다.이 문제를 해결할 수 있습니까 ??
kashif

1
@kashif-실제로 당신에게 문제가 있습니까? 하루에 1,000 개의 ID 값을 사용하더라도 가치가 떨어지려면 2 백만일이 걸립니다. 이전 동작을 원하면 추적 플래그 272로 시작하도록 SQL Server를 설정하거나 SEQUENCE대신 a 를 사용 IDENTITY하고 캐시 크기가 0.
Martin Smith

내 솔루션에 대해 대단히 인상적이고 만족스러운 답변을 많이 받았습니다.
kashif

실제로 당신 CREATE TABLE은 당신이 사용 numeric(7)하고 있고 번호 매기기를 시작 1200001했다는 것은 8,799하루에 1,000을 사용하면 며칠 (24 년) 후에 다 소모된다는 것을 의미합니다 .
Martin Smith

실제 값 "jumped"는 사용 된 열 유형에 따라 달라집니다. 예를 들어 big int열은 일반적으로 다시 시작할 때마다 10,000 씩 "점프"합니다.
StarPilot 2014 년

60

이 문제는 SQL Server를 다시 시작한 후에 발생합니다.

해결책은 다음과 같습니다.

  • SQL Server 구성 관리자를 실행합니다 .

  • SQL Server 서비스를 선택 합니다 .

    SQL Server 구성 관리자

  • SQL Server를 마우스 오른쪽 버튼으로 클릭 하고 속성을 선택 합니다.

  • 시작 매개 변수 아래의 시작 창에서 추가를 입력 -T272하고 클릭 한 다음 적용 버튼 을 누르고 다시 시작합니다.

    SQL Server 시작 매개 변수


1
이 방법은 정말 효과가 있습니다. 감사합니다! 이야기로하고 여기에 ,이 문제는 SQL 서버 2012에 고정되지 않고, 그것의 서비스 팩에, - 만 다음 버전 릴리스한다.
Fragment

2
개별 데이터베이스에 추적 플래그를 적용하는 방법이 있습니까? 타사 데이터베이스가 있고 이것이 어떻게 영향을 미칠지 모르겠 기 때문에 전체 서버에서이 변경을 수행하고 싶지 않습니다.
Ege Ersoz

1
이유를 따르지 않았지만 일부 사용자는 소문자 "t"를 사용해야 작동합니다. 위의 주석에서 Fragment가 게시 한 링크를 참조하십시오.
야만인

33

에서 SQL Server 2017+당신은 사용할 수 ALTER DATABASE의 범위 구성 :

IDENTITY_CACHE = {ON | 끄기}

데이터베이스 수준에서 ID 캐시를 활성화하거나 비활성화합니다. 기본값은 ON입니다. ID 캐싱은 ID 열이있는 테이블에서 INSERT 성능을 향상시키는 데 사용됩니다. 서버가 예기치 않게 다시 시작되거나 보조 서버로 장애 조치되는 경우 ID 열 값의 간격을 방지하려면 IDENTITY_CACHE 옵션을 비활성화합니다. 이 옵션은 서버 수준이 아닌 데이터베이스 수준에서 설정할 수 있다는 점을 제외하면 기존 SQL Server 추적 플래그 272와 유사합니다.

(...)

G. IDENTITY_CACHE 설정

이 예에서는 ID 캐시를 비활성화합니다.

ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE=OFF ;

25

내 대답이 파티에 늦을 수도 있다는 것을 알고 있습니다. 하지만 SQL Server 2012에서 시작 저장 프로 시저를 추가하여 다른 방법으로 해결했습니다.

마스터 DB에 다음 저장 프로 시저를 만듭니다.

USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[ResetTableNameIdentityAfterRestart]
AS
BEGIN

begin TRAN
    declare @id int = 0
    SELECT @id =  MAX(id) FROM [DatabaseName].dbo.[TableName]
    --print @id
    DBCC CHECKIDENT ('[DatabaseName].dbo.[TableName]', reseed, @id)
Commit

END

그런 다음 다음 구문을 사용하여 시작에 추가하십시오.

EXEC sp_procoption 'ResetOrderIdentityAfterRestart', 'startup', 'on';

테이블이 적을 경우 좋은 생각입니다. 그러나 많은 테이블에 대해 수행해야하는 경우이 방법은 여전히 ​​작동하지만 좋은 생각은 아닙니다.


좋은 아이디어. 그러나 종속 테이블에서는 작동하지 않습니까? 내 말은, 외래 키 값을 수정하지 않습니까?
rom5jp

@ rom5jp FK 수정은이 답변의 요점이 아닙니다. 테이블의 가능한 다음 PK 값을 수정하는 것이 전부입니다. MAX (id)가 FK에없는 한 작동합니다.
Jeyara

14

이것은 크기에 관계없이 많은 개발자와 응용 프로그램에서 여전히 매우 일반적인 문제입니다.

안타깝게도 위의 제안은 모든 시나리오 (예 : 공유 호스팅)를 수정하지 않습니다. 호스트에 의존하여 -t272 시작 매개 변수를 설정할 수 없습니다.

또한 기본 키에 이러한 ID 열을 사용하는 기존 테이블이있는 경우 해당 열을 삭제하고 BS 시퀀스 해결 방법을 사용하기 위해 새 열을 다시 만드는 것은 엄청난 노력입니다. Sequence 해결 방법은 SQL 2012+에서 처음부터 새로운 테이블을 디자인하는 경우에만 유용합니다.

결론은 Sql Server 2008R2를 사용하는 경우 계속 유지한다는 것입니다. 진지하게, 그것에 머물러 라. Microsoft가 Sql Server 2016에도 여전히 존재하는 거대한 버그를 도입했다고 인정할 때까지, 그들이 소유하고 IT를 수정하기 전까지는 업그레이드하지 말아야합니다.

Microsoft는 곧바로 주요 변경 사항을 도입했습니다. 즉, 시스템을 다시 시작할 때 현재 ID를 잊어 버리기 때문에 더 이상 설계된대로 작동하지 않는 작동하는 API가 손상되었습니다. 캐시 또는 캐시 없음, 이것은 허용되지 않으며 Bryan이라는 이름의 Microsoft 개발자가 "디자인"및 "기능"이라고 세상에 알리는 대신이를 소유해야합니다. 물론 캐싱은 기능이지만 다음 ID가 무엇이어야하는지 추적하지 못하는 것은 기능이 아닙니다. 끔찍한 벌레 다 !!!

내 DB가 공유 호스팅 서버에 있기 때문에 내가 사용한 해결 방법을 공유 할 것입니다. 또한 기본 키 열을 삭제하고 다시 만들지 않습니다. 이는 거대한 PITA가 될 것입니다.

대신 이것은 내 부끄러운 해킹입니다 (하지만 마이크로 소프트가 도입 한이 POS 버그만큼 부끄럽지는 않습니다).

해킹 / 수정 :

삽입 명령 전에 각 삽입 전에 ID를 다시 시드하십시오. 이 수정은 Sql Server 인스턴스에 대한 관리자 제어 권한이없는 경우에만 권장됩니다. 그렇지 않으면 서버를 다시 시작할 때 다시 시드하는 것이 좋습니다.

declare @newId int -- where int is the datatype of your PKey or Id column
select @newId = max(YourBuggedIdColumn) from YOUR_TABLE_NAME
DBCC CheckIdent('YOUR_TABLE_NAME', RESEED, @newId)

삽입 직전의 3 줄만 있으면됩니다. 실제로 성능에 그다지 영향을 미치지 않습니다. 즉, 눈에 띄지 않을 것입니다.

행운을 빕니다.


7

ID 값을 점프하는 데는 여러 가지 이유가 있습니다. 롤백 된 삽입에서 복제를위한 ID 관리에 이르기까지 다양합니다. 귀하의 경우이 원인은 시스템에서 시간을 보내지 않고는 말할 수 없습니다.

그러나 어떤 경우에도 식별 열이 연속적이라고 가정 할 수 없다는 것을 알아야합니다. 갭을 유발할 수있는 것이 너무 많습니다.

이에 대한 자세한 정보는 http://sqlity.net/en/792/the-gap-in-the-identity-value-sequence/ 에서 찾을 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.