IDENTITY 열에 예기치 않은 간격이 있습니다.


18

1에서 시작하여 1 씩 증가하는 고유 한 구매 주문 번호를 생성하려고합니다.이 스크립트를 사용하여 생성 된 PONumber 테이블이 있습니다.

CREATE TABLE [dbo].[PONumbers]
(
  [PONumberPK] [int] IDENTITY(1,1) NOT NULL,
  [NewPONo] [bit] NOT NULL,
  [DateInserted] [datetime] NOT NULL DEFAULT GETDATE(),
  CONSTRAINT [PONumbersPK] PRIMARY KEY CLUSTERED ([PONumberPK] ASC)    
);

이 스크립트를 사용하여 생성 된 저장 프로 시저 :

CREATE PROCEDURE [dbo].[GetPONumber] 
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO [dbo].[PONumbers]([NewPONo]) VALUES(1);
    SELECT SCOPE_IDENTITY() AS PONumber;
END

작성 당시에는 정상적으로 작동합니다. 저장 프로 시저가 실행될 때 원하는 수에서 시작하여 1 씩 증가합니다.

이상한 점은 컴퓨터를 종료하거나 최대 절전 모드로 전환하면 다음에 프로 시저가 실행될 때 시퀀스가 ​​거의 1000으로 증가했다는 것입니다.

아래 결과를보십시오 :

PO 번호

숫자가 8에서 1002로 증가했음을 알 수 있습니다!

  • 왜 이런 일이 발생합니까?
  • 숫자가 생략되지 않도록하려면 어떻게해야합니까?
  • 필요한 것은 SQL이 다음과 같은 숫자를 생성하는 것입니다.
    • a) 유일한 보장.
    • b) 원하는 양만큼 증가시킵니다.

저는 SQL 전문가가 아니라는 것을 인정합니다. SCOPE_IDENTITY ()의 기능을 이해하지 못합니까? 다른 접근 방식을 사용해야합니까? SQL 2012+에서 시퀀스를 살펴 보았지만 Microsoft는 기본적으로 고유하지 않을 것이라고 말합니다.

답변:


25

이는 SQL Server에서 IDENTITY 열을 관리하는 방식이 SQL Server 2012에서 일부 변경되는 방식으로 알려져 있으며 예상되는 문제입니다 . 기본적으로 1000 값을 캐시하고 SQL Server를 다시 시작하고 서버를 다시 부팅하거나 장애 조치 등을 수행하면 실제로 얼마나 많은 값인지 알 수있는 신뢰할 수있는 방법이 없기 때문에 1000 값을 버려야합니다. 발행 된. 여기에 문서화되어 있습니다 . 모든 IDENTITY 할당이 기록되도록 이러한 동작을 변경하는 추적 플래그가 있습니다 *. 이러한 특정 간격 (롤백 또는 삭제의 간격은 제외)을 방지합니다. 그러나 이것은 성능면에서 상당히 비용이 많이들 수 있으므로 여기서는 특정 추적 플래그에 대해서는 언급하지 않을 것입니다.

* (개인적으로 이것은 다르게 해결할 수있는 기술적 인 문제라고 생각하지만 엔진을 작성하지 않으므로 변경할 수 없습니다.)

IDENTITY와 SEQUENCE의 작동 방식을 명확하게하려면 :

  • 둘 다 고유하지는 않습니다 (기본 키 또는 고유 제한 조건을 사용하여 테이블 레벨에서이를 강제 실행해야 함).
  • 둘 다 틈이 없음을 보장하지는 않습니다 (예를 들어 롤백 또는 삭제시 틈이 생길 수 있음)

독창성은 시행하기 쉽습니다. 차이를 피하는 것은 아닙니다. 이러한 격차를 피하는 것이 얼마나 중요한지 결정해야합니다 (이론적으로 IDENTITY / SEQUENCE 값은 의미없는 대리 키이므로 격차에 전혀 신경 쓰지 않아야합니다). 매우 중요한 경우 두 가지 구현 중 하나를 사용하지 말고 직접 직렬화 가능 시퀀스 생성기를 롤링하십시오 ( 여기 , 여기여기에 몇 가지 아이디어 참조 )-동시성을 죽일 것입니다.

이 "문제"에 대한 배경 지식 :


이 응답 ( "추적 플래그"부분 제외)은 대부분의 다른 SQL 데이터베이스 (어쨌든 시퀀스가있는 데이터베이스)에도 적용됩니다.
mustaccio

답변 해주셔서 감사합니다. 독창성은 가장 중요한 단일 요구 사항입니다. 틈새는 크지 않은 한 크게 중요하지 않습니다. 예를 들어 1에서 4까지는 허용되지만 4에서 1003까지는 허용되지 않습니다.
Ege Ersoz

1
짧은 버전 : ID 값이 구매 주문 번호로 사용됩니다. 고객은 월별 보고서를 실행하고 PO 번호를보고 해당 월에 제출 된 PO 수를 신속하게 알려줄 수 있기를 원합니다. 따라서 ~ 1000 씩 증분 할 수 없습니다 (DB 서버를 포함한 모든 서버가 다시 시작되는 주별 유지 보수가 있습니다).
Ege Ersoz

3
ROW_NUMBER () OVER (PARTITION BY Month ORDER BY ID) 만 사용하는 매우 쉬운 보고서를 제공하지 않는 이유는 무엇입니까? 다시 한번, ID 번호는 의미가 없어야하는데, 이는 얼마나 많은 명령이 내려 졌는지를 안고있는 끔찍한 방법입니다. 코드에 1000 개의 행을 삭제하거나 275 개의 트랜잭션을 롤백하는 버그가 있거나 500 개의 주문이 합법적으로 취소 된 경우 어떻게됩니까?
Aaron Bertrand

1
@Ege : "... PO 번호를보고 몇 명이나 말해주세요". 당신의 사용자는 실망 할 것입니다. 신원 가치는 단순히 그런 식으로 작동하지 않으며, 당신이나 그와 같은 가정을해서는 안됩니다. 독특한? 예. 연속? 아니요. 한 달 동안 제출 된 PO를 계산하는 올바른 방법은 ... 각 레코드의 [변경 불가능한] 날짜 필드를 기준으로 해당 달 동안 제기 된 PO 수를 계산하는 것입니다.
Phill W.

-4

이것은 SQL Server의 문제입니다. 당신이 할 수있는 모든 열을 다시 시드합니다.

열 ID가 잘못된 항목을 삭제하십시오. 열 ID를 다시 시드했습니다. 그리고 다음 항목에는 적절한 ID가 있습니다.

다음 sql 명령을 사용하여 Reseed Identity : DBCC CHECKIDENT ('YOUR_TABLE_NAME', RESEED, 9)-9는 마지막 올바른 ID입니다.


1
"항목 삭제"란 무엇입니까?
ypercubeᵀᴹ September

2
흠 .. 항목을 삭제하면 데이터가 손실 될 수 있습니다.
Michael Green
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.