2009-10-08 4 views
1

다른 번호 유형 중 인시던트 번호를 사용하는 응용 프로그램이 있습니다. 이 숫자는 카운터의 현재 값을 포함하는 "Number_Setup"테이블에 저장됩니다.SQL 서버 데이터베이스에서 고유 번호 확인

응용 프로그램에서 새 인시던트를 생성하면 number_setup 테이블에서 필수 카운터 행을 가져옵니다 (카운터는 매일, 매주 등 재설정 될 수 있으며 int로 저장됩니다). 그런 다음 카운터를 증가시키고 새 값으로 행을 업데이트합니다.

응용 프로그램은 다중 사용자 (한 번에 약 100 명의 사용자뿐 아니라 100 개의 문제 레코드를 실행하고 각각의 인시던트 번호를 요청하는 SQL 작업)입니다. 인시던트 테이블에는 중복되지 않아야하는 중복 인시던트 번호가 있습니다.

저장된 proc은 다음 카운터를 검색하는 데 사용됩니다.

 
SELECT @Counter = counter, @ShareId=share_id, @Id=id 
FROM Number_Setup 
WHERE [email protected] 
AND Counter_Type='I' 

IF isnull(@ShareId,0) > 0 
BEGIN 
    -- use parent counter 
    SELECT @Counter = counter, @ID=id 
    FROM Number_Setup 
    WHERE [email protected] 
END 

SELECT @NewCounter = @Counter + 1 

UPDATE Number_Setup SET Counter = @NewCounter 
WHERE [email protected] 

지금 포위 한 그 거래와 블록,하지만 난 카운터 어쨌든 읽을 수 있도록 여전히 공유 잠금이 있다고 생각대로 '100 %, 문제가 해결됩니다 완전히 확실하지 않다.

아마도 내가 UPDATE 문

 
UPDATE Number_Setup SET Counter = @NewCounter 
WHERE Counter = @Counter 
IF @@ERROR = 0 AND @@ROWCOUNT > 0 
    COMMIT TRANSACTION 
ELSE 
    ROLLBACK TRANSACTION 

나는이
내가 넣을 수없는 등 금융 애플리케이션에서 송장 번호가 일반적인 문제입니다 확신에서, 카운터가 업데이트되지 않았 음을 확인하실 수 있습니다 코드의 논리와 그 수준에서 잠금을 사용하십시오. 나는 또한 홀록 (HOLDLOCK)에 잠겨 있었지만 응용이 확실치 않습니다. 두 개의 SELECT 문에 넣어야합니까?

복제본이 생성되지 않도록하려면 어떻게해야합니까?

+0

어떤 버전의 Sql Server입니까? – RBarryYoung

+0

현재, 2000. –

답변

4

트릭은 카운터 업데이트를하고 하나의 원자 작업으로 읽을 수 있습니다 :

UPDATE Number_Setup SET Counter = Counter+1 
OUTPUT INSERTED.Counter 
WHERE [email protected]; 

이 비록 @NewCounter에 새 카운터를 지정하지 않는 대신 클라이언트로 설정 한 결과를 반환 .할당해야 할 경우 중간 테이블 변수를 사용하여 새 카운터 INTO를 출력하십시오.

declare @NewCounter int; 
declare @tabCounter table (NewCounter int); 
UPDATE Number_Setup SET Counter = Counter+1 
OUTPUT INSERTED.Counter INTO @tabCounter (NewCounter) 
WHERE [email protected] 
SELECT @NewCounter = NewCounter FROM @tabCounter; 

이렇게하면 카운터 증가량을 원자 적으로 만드는 문제가 해결됩니다. LinkTo_Id 및 share_id는 첫 번째 선택 후 여전히 업데이트 될 수 있으므로 잘못된 링크 대상 항목의 카운터를 증가시킬 수는 있지만이 코드 샘플에서 카운터에 따라 달라질 수는 없기 때문에 여전히 다른 경쟁 조건이 있습니다. shared_id 및/또는 LinkTo_Id를 실제로 업데이트하는 코드.

둘째, 일관된 대소 문자로 필드 이름을 지정해야합니다. 인 경우 일관되게 이름을 지정하면 이 T-SQL 코드의 대/소문자를 사용해야합니다. 대소 문자를 구분하지 않는 데이터 정렬 서버가 있기 때문에 스크립트가 올바르게 실행됩니다. 대소 문자를 구분하는 데이터 정렬 서버에 배포하고 스크립트가 필드/테이블 이름의 정확한 대소 문자와 일치하지 않는 경우 오류가 많이 발생합니다.

+0

피드백에 감사드립니다. 스키마는 우리가 제어 할 수 없으며, 필자의 예제는 필드 이름을 만들었고 실제 sproc의 직접적인 복사본이 아닙니다 :) –

+0

매우 감사합니다. –

0

고유 식별자로 자동 증가 대신 GUID를 사용해 보셨습니까?

0

여러 레코드를 가져 오는 작업을 수정할 능력이 없다면 카운터가 ID 열이되도록 생각을 바꿀 것입니다. 다음 레코드를 얻을 때 삽입을 수행하고 테이블의 @@ ID를 얻을 수 있습니다. 그러면 가장 큰 숫자를 얻을 수 있습니다. ID를 재설정하려는 경우 테이블을 업데이트하는 대신 카운터를 재설정하려면 dbccReseed를 수행해야합니다. 유일한 문제는 ID 그룹을 얻기 위해 SQL 작업의 일부로 100 개 정도 삽입해야한다는 것입니다. 너무 많은 오버 헤드가있을 수 있지만 식별 열을 사용하면 고유 한 숫자를 얻는 것이 좋습니다.

+1

방금 ​​생성 한 ID를 다시 얻으려면 scope_identity()가 @@ identity보다 좋을 것입니다. – adrianbanks

0

내가 누락되었지만 대부분의 데이터베이스에서 이미 해결 된 기술을 재발견하려는 것 같습니다.

Number_Setup 테이블의 'Counter'열에서 읽고 업데이트하는 대신 카운터에 기본 키를 자동 증가시키지 않는 이유는 무엇입니까? 기본 키에 대해 중복 값을 가질 수 없습니다.

+0

은 카운터가 매일, 달 또는 기타 고객 정의 기간을 재설정하는 숫자를 생성해야하기 때문에 발생합니다. 다른 고객에게는 매일 재설정되는 인시던트 번호가 있으며 재설정되지 않는 인시던트 번호가 있습니다. 인시던트 번호는 인시던트 테이블의 필드에 배치됩니다. 해당 필드는 고유하지 않고 색인이 생성됩니다. 기존의 저장된 proc가 10 년 넘게 준비되어 있습니다 :) –