6

考虑到 SQL Azure 联合不支持 IDENTITY 属性或序列,在插入记录时生成序列号的有效方法是什么?

例如,给定一个包含这些列的表:

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 是联邦的分发密钥。

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

考虑到可扩展性、争用、资源锁定,这是否是最佳方法?考虑到 SQL Azure 联合的限制,还有其他有用的技巧吗?

4

2 回答 2

2

这里有 2 个额外的想法。

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

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

于 2012-03-12T02:42:38.413 回答
2

不确定需要多少努力才能适应您的场景,但也可以看看这个,看看您是否可以调整它:SnowMaker – Azure 的唯一 id 生成器(或任何其他云托管环境)

于 2012-03-12T06:34:24.860 回答