Eu tenho um requisito para criar um procedimento armazenado que emule uma sequência TSQL. Ou seja, sempre fornece um valor inteiro distinto crescente em cada chamada. Além disso, se um inteiro for passado, ele deve retornar esse valor se nunca houver um resultado maior ou o próximo inteiro mais alto disponível. Escusado será dizer que pode haver vários clientes ligando para este SP ao mesmo tempo.
Dada uma tabela MetaInfo com colunas MetaKey varchar(max) e MetaValueLong 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 é simples: esse procedimento armazenado funciona conforme o esperado (todos os chamadores receberão um resultado exclusivo)?
Dei uma olhada e a própria Microsoft oferece uma solução sem travas:
Número de Sequência do SQL Server
Esta é uma atualização simples sem dicas de bloqueio, mas eles dizem que trava/trava.
Nada muito sobre SO sobre isso também.
Eu estaria inclinado a adicionar
UPDLOCK
ao seuROWLOCK
(conforme "mesa como uma fila" (SO), mas semREADPAST
). 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 duvidar.
READPAST
permite simultaneidade segura, mas neste caso é inútil.Nota: você pode usar a
OUTPUT
cláusula em vez de um segundo select, então não precisa da transação.O seguinte está faltando
Sim, deve atender a sua condição. Uma vez que tais situações ocorrem em transações, ele cria suas múltiplas instâncias e, subsequentemente, todos os chamadores receberão um resultado único
Uma solução mais escalável que não requer serialização é esta: