【问题标题】:How to generate a unique numeric ID in SQL Server (not using identity)?如何在 SQL Server 中生成唯一的数字 ID(不使用标识)?
【发布时间】:2020-11-12 08:55:53
【问题描述】:

我的表需要一个唯一的编号 ID。通常我会在 Sql Server 中使用 Identity,但我的用例有一个问题。我想在创建行之前知道 id(以便能够在将所有内容提交到数据库之前在内存中的其他记录中引用它)。

我不知道是否可以通过 Identity 实现,但我想不通。

所以我的下一个最佳猜测是我需要一个表来存储一个值并不断增加它并返回一个新的 id 值。必须锁定访问权限,这样两个操作才能获得相同的值。

我正在考虑使用例如sp_getapplock @Resource = 'MyUniqueId' 以防止将相同的号码返回给呼叫者。也许我也可以在事务中使用普通锁定。

有没有更好的方法来解决这个问题?

【问题讨论】:

  • 您可以使用 SEQUENCE 从服务器检索新的唯一值。你不需要显式锁
  • 是的,看起来正是我需要的,它保证唯一性吗?
  • 确实如此 - 即使回滚事务也不会重置 SEQUENCE。另一方面,如果您明确重置它,它将再次开始产生相同的值。这与重新播种 IDENTITY 没有什么不同
  • 我希望我可以避免重置它:)

标签: sql sql-server uniqueidentifier unique-id


【解决方案1】:

您可以创建一个产生递增值的SEQUENCE 对象。 SEQUENCE 可以单独使用,也可以作为一个或多个表的默认值。

您可以使用CREATE SEQUENCE 创建序列:

CREATE SEQUENCE Audit.EventCounter  
    AS int  
    START WITH 1  
    INCREMENT BY 1 ; 

您可以使用NEXT VALUE FOR 以原子方式检索下一个值,并在多个语句中使用它,例如:

DECLARE @NextID int ;  
SET @NextID = NEXT VALUE FOR Audit.EventCounter; 

回滚事务不会影响 SEQUENCE。来自文档:

序列号是在当前事务范围之外生成的。无论使用序列号的事务是提交还是回滚,它们都会被消耗。

您可以在多个表中使用NEXT VALUE FOR 作为默认值。在文档示例中,三种不同类型的事件表使用相同的 SEQUENCE 允许所有事件获得唯一编号:

CREATE TABLE Audit.ProcessEvents  
(  
    EventID int PRIMARY KEY CLUSTERED   
        DEFAULT (NEXT VALUE FOR Audit.EventCounter),  
    EventTime datetime NOT NULL DEFAULT (getdate()),  
    EventCode nvarchar(5) NOT NULL,  
    Description nvarchar(300) NULL  
) ;  
GO  
  
CREATE TABLE Audit.ErrorEvents  
(  
    EventID int PRIMARY KEY CLUSTERED  
        DEFAULT (NEXT VALUE FOR Audit.EventCounter),  
    EventTime datetime NOT NULL DEFAULT (getdate()),  
    EquipmentID int NULL,  
    ErrorNumber int NOT NULL,  
    EventDesc nvarchar(256) NULL  
) ;  
GO  
  
CREATE TABLE Audit.StartStopEvents  
(  
    EventID int PRIMARY KEY CLUSTERED  
        DEFAULT (NEXT VALUE FOR Audit.EventCounter),  
    EventTime datetime NOT NULL DEFAULT (getdate()),  
    EquipmentID int NOT NULL,  
    StartOrStop bit NOT NULL  
) ;  
GO  

【讨论】:

    【解决方案2】:

    这里的一个选项是使用 UUID 来表示每个唯一记录。如果要在 SQL Server 中生成 UUID,可以使用 NEWID() 函数(有关详细信息,请参阅 documentation)。如果此值是从您的应用程序代码生成的,您可以在 SQL Server 中使用 CONVERT 将其转换为 uniqueidentifier 类型。

    作为参考,UUID 是一个 16 字节的唯一标识符。 您的应用程序或 SQL Server 不会多次生成相同的 UUID。它们看起来像这样:

    773c1570-1076-4e19-b728-6d7b0b20895a
    

    【讨论】:

    • 这会很快导致索引碎片。至少应该在客户端使用NEWSEQUENTIALID 或等效项
    • 是的,我曾考虑过使用 UUID,但据我所知,使用 UUID 作为主键会使所有未来的连接/搜索速度比数字慢
    【解决方案3】:

    如果您想要与 IDENTITY 列匹配的行为,请尝试:

    CREATE SEQUENCE mydb.dbo.mysequence;

    然后,重复:

    SELECT NEXT VALUE FOR mysequence;

    而且,如果你想玩更多,请看这里:

    https://docs.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql?view=sql-server-ver15

    玩的开心……

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-14
      • 1970-01-01
      • 2017-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-16
      相关资源
      最近更新 更多