在SQL Azure Federations上生成序列号的有效方法

Fer*_*eia 6 sequence federation azure-sql-database

考虑到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])
Run Code Online (Sandbox Code Playgroud)

对于为给定租户插入的每个订单,OrderId应递增.例如,对于帐篷来说,OrderId将是1,2,3 ......而对于租户B,OrderId也将是1,2,3 ......在一个独立的序列中.理想情况下应该没有差距.

TenantId和OrderId是主键的组件.它们的值由应用程序设置,它们与生成序列的问题无关; 只有OrderId具有具有商业含义的序号.此外,TenantId是联合的分发密钥.

该MSDN博客文章在选项1中描述了一种方法,即使用表保存序列并在隔离事务中使用存储过程来递增序列.每个租户在此表上都有一条记录,其中包含序列的最后一个使用值.

考虑到可扩展性,争用,资源锁定,这会是最佳方法吗?考虑到SQL Azure Federations的局限性,还有其他任何有用的技巧吗?

Her*_*ero 2

这里有两个额外的想法。

一种方法是让一个单独的流程更新该字段以使其异步(如果这对于您的业务场景来说是可能的)。对于这种方法,您需要让 OrderNumber 字段接受 NULL 值。为了知道哪个订单最先出现,以便它获得正确的 OrderNumber,我还会添加一个 InsertedDate 字段。如果您有多个工作角色执行此冗余职责,则异步处理会变得更加复杂,在这种情况下,您将需要让每个进程为自己分配其正在处理的记录(因此您还需要一个 OwnedBy 字段),在期间添加并发测试UPDATE 确保每个进程都在自己的记录上执行,并且在进程崩溃时让记录的分配过期(因此您还需要一个AssignedOn 字段),这样就不会留下孤儿。其实不是小事...

然后你就有了穷人的方法……当星星排列得足够好时,这可能就是你所需要的。如果您愿意采用乐观并发方法,请尝试在插入期间使用下一个数字(首先为给定的 TenantId 和 OrderId 选择 MAX OrderNumber),然后执行插入。如果插入失败(因为您为此目的在 TenantId、OrderNumber 上添加了唯一索引),只需将 OrderNumber 加 1 即可。这里真正的问题是重试的频率以及这种方法失败的可能性。如果您有一个相对精简的业务流程,这实际上可能永远不会失败;然而,如果您不断从多个渠道添加订单,这可能是一种不可接受的方法。