Sql server SQL Server自动递增每个客户(租户)的标识,无任何间隙

Sql server SQL Server自动递增每个客户(租户)的标识,无任何间隙,sql-server,uniqueidentifier,Sql Server,Uniqueidentifier,我们有一个多租户数据库,其中包含多个客户,每个客户都有一个这样的用户集合(简化示例省略了从用户到客户的外键规范): 作为本设计的一部分,用户需要有一个成员编号,当我们设计本设计时,我们决定使用UserId作为成员编号,但是由于所有的原因,这一要求已经增加,并且这不再是一个选项,原因有二: 在每次服务器重启升级到2012年后,该列的值都会增加1000,我们使用了此处显示的解决方法:(-t272)来阻止这种情况发生,但这让我们意识到标识(1,1)不够好 我们现在真正想要的是确保每个客户的数量增加,但

我们有一个多租户数据库,其中包含多个客户,每个客户都有一个这样的用户集合(简化示例省略了从用户到客户的外键规范):

作为本设计的一部分,用户需要有一个成员编号,当我们设计本设计时,我们决定使用UserId作为成员编号,但是由于所有的原因,这一要求已经增加,并且这不再是一个选项,原因有二:

  • 在每次服务器重启升级到2012年后,该列的值都会增加1000,我们使用了此处显示的解决方法:(-t272)来阻止这种情况发生,但这让我们意识到标识(1,1)不够好

  • 我们现在真正想要的是确保每个客户的数量增加,但它必须是永久性的,并且在分配后不能更改

  • 很明显,序列将无法工作,因为它需要按每个客户执行。我们还需要对每个客户/用户执行唯一的约束,并确保值在分配后不会更改,并且在删除用户时不会更改(虽然这不应该发生,因为我们不会删除用户,而是将其标记为已存档,但是我想保证这不会影响它)

    下面是我所写的可以生成数字的示例,但是使用此方法或类似方法的最佳方式是什么,以确保每个客户/用户都有一个唯一的、连续的价值,而不会出现任何问题,因为用户可以在同一时间从不同的会话中创建

      ROW_NUMBER() OVER (ORDER BY i.UserId) + ISNULL((SELECT MAX(users.MembershipNumber)
                                                        FROM [User].Users users
                                                       WHERE users.Customers_CustomerId = i.Customers_CustomerId), 0)
    
    编辑:澄清


    我很抱歉,我只是重新阅读了我的问题,我没有说得足够清楚,我们不希望替换UserId,我们对所有外键上使用的每个数据库标识符的间隔和唯一性感到满意,我们希望添加的是一个将显示给用户的成员身份号,这就是为什么它需要按客户顺序排列没有间隙,因为此会员编号将用于提供给用户的卡上,因此需要是唯一的。

    既然您已经发现了标识栏的问题以及如何解决它,我不会说它不够好。
    但是,它似乎不适合您的需要,因为您希望每个客户的用户数量都增加

    我建议将用户列保留为标识列和表的主键,并添加另一列以按客户指定用户编号。此列也将是一个整数,默认值为将计算每个客户下一个编号的
    UDF

    您可以通过在users表上使用instead of update触发器来保护该值不受任何更改

    这种方法可以保留一个单列主键,只要每个客户都有一个唯一的、连续的用户编号

    更新
    显然,

    但是您仍然可以使用
    而不是insert
    触发器来实现您的目标。

    这是因为序列对象的默认缓存sqlserver实现。请参阅前一个线程


    如果间隙是一个问题,sql-server2012引入了Sequence对象。您可以使用NOCACHE声明这些对象,因此重新启动服务器不会产生间隙。

    我想分享我的想法。请参见下面的内容

  • 创建一个单独的表,它将保存CustomerID和如下所示的计数列

    CREATE TABLE dbo.CustomerSequence
    (
       @CustomerID int,
       @Count  int
    );
    
    CREATE PROC dbo.usp_GetNextValueByCustomerID
          @CustomerID int,
          @Count int OUTPUT
    AS
    BEGIN
        UPDATE dbo.CustomerSequence
        SET @Count = Count += Count
        WHERE CustomerID = @CustomerID;
    
    END
    
  • 编写一些存储过程,如下所示

    CREATE TABLE dbo.CustomerSequence
    (
       @CustomerID int,
       @Count  int
    );
    
    CREATE PROC dbo.usp_GetNextValueByCustomerID
          @CustomerID int,
          @Count int OUTPUT
    AS
    BEGIN
        UPDATE dbo.CustomerSequence
        SET @Count = Count += Count
        WHERE CustomerID = @CustomerID;
    
    END
    
  • 只需通过传递CustomerID调用上面存储的proc,并从中获取下一个序列值


  • 为什么你会介意每个客户都有一个系列?这不只是某种ID吗?你的解决方案可能会奏效,但我不喜欢SELECT MAX()因为只有当您的数据库设置为始终锁定时,它才真正起作用。理想情况下,您会使用快照隔离,这会减少争用,但会引入这样的问题。就我个人而言,我只需要按照顺序来处理间隙。不要担心间隙-它们真的不是问题!谢谢您的回答,我已经编辑了在阅读了您的编辑后,我仍然认为我的答案完全满足了您的需求。如果您不这么认为,请在评论中告诉我,以便我可以尝试改进。我已经尝试过这样做,但我似乎无法像传递列值那样将CustomerId传递给默认约束函数带有检查约束。如果函数中的行没有客户Id,它将无法工作。我们使用了Insert而不是Insert触发器,这并不理想,但看起来是唯一的解决方法。很高兴我能提供帮助!如果您找到更好的解决方案,我想了解一下。