我有一个系统,要求我在数据进入数据库之前拥有数据的 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
“序列”表只是序列的 ID、名称(唯一)和最后分配的值。使用此过程,我可以请求命名序列中的 N 个值,并将它们用作我的标识符。
到目前为止,这效果很好 - 速度非常快,因为我不必不断地要求单独的值,我可以用完一系列值,然后要求更多。
问题在于,在极高频率下,并发调用该过程有时会导致死锁。我只在压力测试时发现这种情况,但我担心它会在生产中突然出现。此过程是否存在任何明显的缺陷,有人可以推荐任何改进方法吗?例如,如果没有事务就很好,但我确实需要它是“线程安全的”。
最佳答案
MS themselves offer a solution甚至他们说它会锁定/死锁。 如果您想添加一些锁定提示,那么您需要减少高负载的并发性
选项:
- 您可以针对下一个版本的“Denali”CTP 进行开发
- 像其他人一样使用 IDENTITY 和 OUTPUT 子句
- 采用/修改上述解决方案
在 DBA.SE 上有 "Emulate a TSQL sequence via a stored procedure" :请参阅 dportas 的答案,我认为它扩展了 MS 解决方案。
关于sql-server - SQL Server - 实现序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6750614/