Emule uma sequência TSQL por meio de um procedimento armazenado

17

Eu tenho um requisito para criar um procedimento armazenado que emula uma sequência TSQL. Ou seja, sempre fornece um valor inteiro distinto crescente em cada chamada. Além disso, se um número inteiro for passado, ele retornará esse valor se nunca houve um resultado maior ou o próximo número inteiro mais alto disponível. Escusado será dizer que pode haver vários clientes chamando este SP ao mesmo tempo.

Dada uma tabela MetaInfo com as colunas MetaKey varchar (max) e MeatValueLong bigInt. Espera-se que a linha com a MetaKey de 'Internal-ID-Last' contenha o último valor mais alto atribuído. Eu criei o seguinte procedimento armazenado:

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

Minha pergunta é simplesmente: esse procedimento armazenado funciona como esperado (todos os chamadores receberão um resultado exclusivo)?

Hogan
fonte
@all: FYI, gerado por este Q no SO: stackoverflow.com/q/6342732/27535
gbn

Respostas:

8

Eu já dei uma olhada e o próprio MS oferece uma solução sem bloqueios

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

Esta é uma atualização simples, sem dicas de bloqueio, mas eles dizem que ela bloqueia / deadlocks.

Nada muito sobre isso também.

Eu estaria inclinado a adicionar UPDLOCK ao seu ROWLOCK (conforme "tabela como uma fila" (SO), mas sem READPAST). Isso aumentará o isolamento caso um segundo processo comece a ler.

No entanto, o fato de todos os seus processos quererem ler / gravar a mesma linha me faz adivinhar. O READPAST permite simultaneidade segura, mas neste caso é inútil.

Nota: você pode usar a cláusula OUTPUT em vez de uma segunda seleção e não precisará da transação.

HTH ...

gbn
fonte
1
Você chegou antes de mim. Observe que o SQL Server 2011 inclui a funcionalidade SEQUENCE, portanto, o requisito de inventar o seu deve desaparecer em breve (não antes do tempo).
Nvogel
@portport: de fato. E funciona melhor também: dba.stackexchange.com/q/1635/630
gbn
@dportas - o SEQUENCE pode permitir requisitos de entrada? Na minha leitura rápida do recurso, não vi essa funcionalidade.
Hog #
1

Faltam as seguintes coisas

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

Sim, deve atender a sua condição. Quando essas situações ocorrem nas transações, ele cria várias instâncias e, posteriormente, todos os chamadores receberão um resultado exclusivo

Pankaj
fonte
Se eu confirmar antes da seleção, não há uma possibilidade, selecionarei o resultado salvo por uma chamada diferente?
Hogan
Não tenho certeza. Mas parece que você está certo. Eu preciso checar. Obrigado. Entre +1 e, Boa pergunta ...
0

Uma solução mais escalável que não requer serialização é a seguinte:

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;
nvogel
fonte
OP tem uma exigência para permitir aos usuários passar em um valor que complica-lo ...
gbn
@dportas - Obrigado. Eu estava ciente dessa abordagem, mas ela não funciona aqui por causa do parâmetro de entrada.
Hogan
@ Hogan, eu modifiquei minha sugestão para lidar com o parâmetro de entrada. É principalmente não testado embora.
Nvogel
@dportas - A chamado com inID de 500, B chamado com inID de 50 - ação - A retorna com 51, B com 52. Falha no requisito.
Hog #
Interessante. Eu obtenho resultados diferentes (em 2008r2). Você pode publicar a reprodução completa com DDL e indicar sua versão / compilação.
Nvogel