Bar*_*ast 5 t-sql sql-server sequence
我有一个系统,要求我在进入数据库之前对我的数据有ID.我使用的是GUID,但发现它们太大而不方便.
我现在正在尝试实现一个序列生成器,它基本上为给定的上下文保留了一系列唯一ID值.代码如下;
ALTER PROCEDURE [dbo].[Sequence.ReserveSequence]
@Name varchar(100),
@Count int,
@FirstValue bigint OUTPUT
AS
BEGIN
SET NOCOUNT ON;
-- Ensure the parameters are valid
IF (@Name IS NULL OR @Count IS NULL OR @Count < 0)
RETURN -1;
-- Reserve the sequence
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION
-- Get the sequence ID, and the last reserved value of the sequence
DECLARE @SequenceID int;
DECLARE @LastValue bigint;
SELECT TOP 1 @SequenceID = [ID], @LastValue = [LastValue]
FROM [dbo].[Sequences]
WHERE [Name] = @Name;
-- Ensure the sequence exists
IF (@SequenceID IS NULL)
BEGIN
-- Create the new sequence
INSERT INTO [dbo].[Sequences] ([Name], [LastValue])
VALUES (@Name, @Count);
-- The first reserved value of a sequence is 1
SET @FirstValue = 1;
END
ELSE
BEGIN
-- Update the sequence
UPDATE [dbo].[Sequences]
SET [LastValue] = @LastValue + @Count
WHERE [ID] = @SequenceID;
-- The sequence start value will be the last previously reserved value + 1
SET @FirstValue = @LastValue + 1;
END
COMMIT TRANSACTION
END
Run Code Online (Sandbox Code Playgroud)
"序列"表只是一个ID,名称(唯一),以及序列的最后一个分配值.使用此过程,我可以在命名序列中请求N个值,并将它们用作我的标识符.
到目前为止这种方法效果很好 - 它非常快,因为我不必经常询问单个值,我可以使用一系列值然后请求更多.
问题是,在极高的频率下,同时调用该过程有时会导致死锁.我只是发现压力测试会发生这种情况,但我担心它会在生产中出现.这个过程中是否有任何明显的缺陷,任何人都可以推荐任何改进方法吗?例如,没有事务就可以了,但我确实需要这是'线程安全的'.
我想我会分享我的解决方案。我不会死锁,也不会产生重复的值。这个过程和我原来的过程之间的一个重要区别是,如果队列尚不存在,它不会创建队列。
ALTER PROCEDURE [dbo].[ReserveSequence]
(
@Name nvarchar(100),
@Count int,
@FirstValue bigint OUTPUT
)
AS
BEGIN
SET NOCOUNT ON;
IF (@Count <= 0)
BEGIN
SET @FirstValue = NULL;
RETURN -1;
END
DECLARE @Result TABLE ([LastValue] bigint)
-- Update the sequence last value, and get the previous one
UPDATE [Sequences]
SET [LastValue] = [LastValue] + @Count
OUTPUT INSERTED.LastValue INTO @Result
WHERE [Name] = @Name;
-- Select the first value
SELECT TOP 1 @FirstValue = [LastValue] + 1 FROM @Result;
END
Run Code Online (Sandbox Code Playgroud)