考虑到 SQL Azure 联合不支持 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 应递增。例如,对于租户 A 而言,OrderId 将为 1, 2, 3...,而对于租户 B 而言,OrderId 也将为 1, 2, 3...,以独立的顺序。理想情况下不应有间隙。
TenantId 和 OrderId 是主键的组成部分。它们的值由应用程序设置,与生成序列的问题无关;只有OrderId具有商业意义的序号。另外,TenantId 是联邦的分发 key 。
This MSDN Blog article选项 1 中描述了一种方法,该方法使用一个表保存序列并在隔离事务中使用存储过程来递增序列。每个租户都会在此表上有一条记录,保存序列的最后使用的值。
考虑到可扩展性、争用、资源锁定,这是否是最佳方法?考虑到 SQL Azure 联合的限制,还有其他有用的技巧吗?
最佳答案
这里有 2 个额外的想法。
一种方法是让一个单独的流程更新该字段以使其异步(如果这对于您的业务场景来说是可能的)。对于这种方法,您需要让 OrderNumber 字段接受 NULL 值。为了知道哪个订单最先出现,以便它获得正确的 OrderNumber,我还会添加一个 InsertedDate 字段。如果您有多个辅助角色执行此冗余职责,则异步处理会变得更加复杂,在这种情况下,您将需要让每个进程为自己分配其正在处理的记录(因此您还需要一个 OwnedBy 字段),在期间添加并发测试UPDATE 确保每个进程都在自己的记录上执行,并且在进程崩溃时让记录的分配过期(因此您还需要一个AssignedOn 字段),这样就不会留下孤儿。确实不是微不足道的...
然后你就有了穷人的方法......当星星排列得足够好时,这可能就是你所需要的。如果您愿意采用乐观并发方法,请尝试在插入期间使用下一个数字(首先为给定的 TenantId 和 OrderId 选择 MAX OrderNumber),然后执行插入。如果插入失败(因为您为此目的在 TenantId、OrderNumber 上添加了唯一索引),只需将 OrderNumber 加 1 即可。这里真正的问题是重试的频率以及这种方法失败的可能性。如果您有一个相对精简的业务流程,这实际上可能永远不会失败;但是,如果您不断从多个 channel 添加订单,这可能是一种 Not Acceptable 方法。
关于sequence - 在 SQL Azure 联合上生成序列号的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9642916/