考虑到SQL Azure Federations不支持IDENTITY属性或SEQUENCE,在插入记录时生成序列号的有效方法是什么?
例如,给定一个包含这些列的表:
CREATE TABLE [dbo].[Orders] (
[TenantId] [uniqueidentifier] NOT NULL,
[OrderId] [uniqueidentifier] NOT NULL,
[OrderNumber] [int] NOT NULL
CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED (
[TenantId] ASC,
[OrderId] ASC
)
) FEDERATED ON ([FederationKey] = [TenantId])
对于为给定租户插入的每个订单,OrderId应递增。例如,对于帐篷来说,OrderId将是1,2,3 ......而对于租户B,OrderId也将是1,2,3 ......在一个独立的序列中。理想情况下应该没有差距。
TenantId和OrderId是主键的组件。它们的值由应用程序设置,它们与生成序列的问题无关;只有OrderId具有具有商业含义的序号。此外,TenantId是联合的分发密钥。
This MSDN Blog article在选项1中描述了一种方法,即使用表来保存序列并在隔离事务中使用存储过程来递增序列。每个租户在此表上都有一条记录,其中包含序列的最后一个使用值。
考虑到可扩展性,争用,资源锁定,这会是最佳方法吗?考虑到SQL Azure Federations的限制,还有其他任何有用的技巧吗?
答案 0 :(得分:2)
以下是另外两个想法。
一种方法是让一个单独的进程更新该字段以使其异步,如果这对您的业务场景是可能的。您需要让OrderNumber字段接受此方法的NULL值。要知道哪个Order首先出现,以便它获得正确的OrderNumber,我还会添加一个InsertedDate字段。如果您有多个工作者角色执行此冗余任务,异步处理会变得更复杂,在这种情况下,您需要让每个进程为自己分配正在处理的记录(因此您还需要OwnedBy字段),在此期间添加并发测试UPDATE确保每个进程在其自己的记录上执行,并且如果进程崩溃以使其不离开孤儿,则记录的分配到期(因此您还需要AssignedOn字段)。不是很琐碎......
然后你有穷人的方法......当星星很好地调整自己时,你可能只需要它。如果您愿意采用乐观并发方法,请在插入期间尝试使用下一个Number(首先为给定的TenantId和OrderId选择MAX OrderNumber),然后执行Insert。如果插入失败(因为您在TenantId上添加了唯一索引,OrderNumber用于此目的),只需将1添加到OrderNumber。这里真正的问题是重试的频率以及这种方法失败的可能性。如果您有一个相对简化的业务流程,这实际上可能永远不会失败;但是,如果您从多个途径不断添加订单,这可能是一种不可接受的方法。
答案 1 :(得分:2)
不确定适合您的方案需要多少工作量,但也要看一下,看看是否可以调整它:SnowMaker – a unique id generator for Azure (or any other cloud hosting environment)