저장 프로 시저를 통해 TSQL 시퀀스 에뮬레이션


17

TSQL 시퀀스를 에뮬레이트하는 저장 프로 시저를 만들어야합니다. 즉, 모든 호출에서 항상 고유 한 정수 값을 제공합니다. 또한 정수가 전달되면 결과가 더 높거나 다음으로 가장 높은 정수가없는 경우 해당 값을 반환해야합니다. 이 SP를 동시에 호출하는 클라이언트가 여러 명있을 수 있습니다.

MetaKey varchar (max) 및 MeatValueLong bigInt 열이있는 MetaInfo 테이블이 제공됩니다. 메타 키가 'Internal-ID-Last'인 행에는 마지막으로 할당 된 가장 높은 값이 포함될 것으로 예상됩니다. 다음 저장 프로 시저를 만들었습니다.

CREATE PROCEDURE [dbo].[uspGetNextID]
(
  @inID bigInt 
)
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRANSACTION

    UPDATE MetaInfo WITH (ROWLOCK) 
      SET MetaValueLong = CASE 
                            WHEN ISNULL(MetaValueLong,0) > @inID THEN MetaValueLong+1 
                            ELSE @inID+1
                          END 
    WHERE MetaKey = 'Internal-ID-Last'

    SELECT MetaValueLong 
    FROM MetaInfo
    WHERE MetaKey = 'Internal-ID-Last'

    COMMIT TRANSACTION 

END

내 질문은 단순히이 저장 프로 시저가 예상대로 작동합니까 (모든 발신자에게 고유 한 결과가 할당 됨)입니까?


@All : FYI, SO에 의해 산란이 Q : stackoverflow.com/q/6342732/27535
GBN

답변:


8

나는 모양을 보았고 MS 자체는 잠금없이 솔루션을 제공합니다.

http://blogs.msdn.com/b/sqlcat/archive/2006/04/10/sql-server-sequence-number.aspx

이것은 잠금 힌트가없는 간단한 업데이트이지만 잠금 / 교착 상태라고 말합니다.

이것에 관해서도 아무것도 없습니다.

ROWLOCK에 UPDLOCK을 추가하는 경향이 있습니다 ( "대기열 테이블"(SO)에 따라 READPAST 제외). 이는 두 번째 프로세스가 읽기를 시작하는 경우 격리를 증가시킵니다.

그러나 모든 프로세스가 동일한 행을 읽고 쓰기를 원한다는 사실은 나를 다시 추측하게 만듭니다. READPAST는 안전한 동시성을 허용하지만이 경우에는 쓸모가 없습니다.

참고 : 두 번째 선택 대신 OUTPUT 절을 사용할 수 있으므로 트랜잭션이 필요하지 않습니다.

HTH ...


1
넌 날 이겼어 SQL Server 2011에는 SEQUENCE 기능이 포함되어 있으므로 자신의 발명에 대한 요구 사항이 곧 사라질 것입니다.
nvogel

@ dportas : 실제로. 그리고 더 나은 너무 실행 : dba.stackexchange.com/q/1635/630
GBN

@dportas-SEQUENCE가 입력 요구 사항을 허용 할 수 있습니까? 기능을 빨리 읽었을 때 그 기능을 보지 못했습니다.
Hogan

1

다음 사항이 누락되었습니다

1. SET XACT_ABORT
2. Exception Handling (Try Catch)

예, 귀하의 상태를 충족해야합니다. 이러한 상황이 거래에 들어 오면 여러 인스턴스를 생성 한 다음 모든 발신자에게 고유 한 결과가 할당됩니다.


선택하기 전에 커밋하면 다른 호출로 저장된 결과를 선택할 수 있습니까?
호건

확실하지 않습니다. 그러나 당신이 옳은 것 같습니다. 확인해야합니다. 감사. BTW +1 for, Good Question ...

0

직렬화를 요구하지 않는보다 확장 가능한 솔루션은 다음과 같습니다.

CREATE PROCEDURE [dbo].[uspGetNextID]
(
  @inID BIGINT OUT
)
AS
      SET NOCOUNT ON
      SET IDENTITY_INSERT SequenceTable ON;
      INSERT INTO SequenceTable (id) VALUES (@inID);
      SET IDENTITY_INSERT SequenceTable OFF;
      INSERT INTO SequenceTable DEFAULT VALUES;
      DELETE FROM SequenceTable WITH (READPAST);
      SET @inID = SCOPE_IDENTITY();
RETURN;

OP는 사용자가 복잡하게하는 가치를 전달할 수 있도록 요구하고 있습니다.
gbn

@ dportas-감사합니다. 이 접근 방식을 알고 있었지만 입력 매개 변수로 인해 여기서 작동하지 않습니다.
Hogan

@Hogan, 입력 매개 변수를 처리하기 위해 제안을 수정했습니다. 그래도 대부분 테스트되지 않았습니다.
nvogel

@dportas-inID 500으로 호출 된 A, inID 50으로 호출 된 B-action-A는 51, 반환 B는 52입니다. 요구 사항이 실패했습니다.
Hogan

흥미 롭군 나는 다른 결과를 얻습니다 (2008r2에서). DDL을 사용하여 전체 재현을 게시하고 빌드 / 버전을 진술 할 수 있습니까?
nvogel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.