如何为同一数据库的不同表生成全局唯一ID?

ige*_*elr 6 sql-server unique-constraint

在 SQL Server 上的生产系统中,所有表中的所有 ID(主要是 PK)都是自动生成的,我被告知它们在全局是唯一的。我的意思是数据库中没有 2 个 ID 是相同的,即使表不同。我想知道如何做到这一点?如果有多种方式,请一一列出。谢谢。

Mic*_*een 13

回到那天,我们有一张ID桌子。单列单行有一个int值。每个事务首先更新该表以获得一个新值,然后在需要的地方使用该值。当然,这是并发错误的重要来源。

后来,引入了序列。整个数据库中使用的单个序列将显示您描述的行为。文档中有一个示例说明了这一点:

CREATE TABLE Audit.ProcessEvents
(
    EventID int DEFAULT (NEXT VALUE FOR Audit.EventCounter), -- same sequence, different table
    <other columns>
);

CREATE TABLE Audit.ErrorEvents
(
    EventID int DEFAULT (NEXT VALUE FOR Audit.EventCounter), -- same sequence, different tables
    <other columns>
);

Run Code Online (Sandbox Code Playgroud)

我已经编辑了示例以突出显示此用法。

通过在应用程序代码中生成全局唯一编号,然后将它们传递到数据库,可以实现相同的结果。如果我要实现这个,我想它会作为编译到可执行文件中的某个实用程序类的静态方法(尽管其他实现是可能的)。假设应用程序需要将客户的详细信息写入数据库。由于它正在编组客户姓名、地址、电话号码等,因此它还会生成一个新的全局 ID。ID 作为另一个参数值传递给 INSERT 语句(或存储过程)。

ID 值是由应用程序架构层还是数据库层生成将取决于特定的设计考虑。如果应用程序可以横向扩展实例之间的协调,就会出现问题。应用程序重新启动后,代码必须找出要使用的下一个值。数据库服务器已经将这些特性和其他特性写入其中。

我绝对不会做的是让应用程序只为下一个 ID 调用数据库,然后将它与业务数据一起编组到 INSERT 中。当只需要一次时,到数据库的往返次数太多了。


Dav*_*ett 7

对于同一个表中的唯一 ID 值,我假设您知道常用IDENTITY选项,通常使用从 1 开始的 32 位值(因此以这种方式定义 PK 类似于ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY)。BIGINT如果表可能需要超过 2,147,483,647 行,您当然可以使用更大的 ( )。

SQL Server 可以选择定义您自己的序列,该序列可以在多个表(可能是所有表)之间共享。有关详细信息,请参阅https://docs.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql。然后将每个 ID 列定义为ID INTEGER DEFAULT NEXT VALUE FOR The_sequence_You_Defined PRIMARY KEY. 不过,这里有一些事情需要注意。不像 with也可以在其他地方使用(即),这意味着如果您需要在应用程序逻辑的其他地方生成 ID,您可以通过这种方式完成(实际上我已经看到这甚至用于单个身份,而不仅仅是共享多个对象之间的序列)。IDENTITY您是,不会阻止删除任何旧值(尚未存在),因为仅当未明确给出序列值时才会默认应用序列值,这可能会产生问题。此外,使用序列的执行速度会稍微慢一些,并且可能成为瓶颈,因为所有表都依赖于同一个对象,尽管如果您的数据库在短时间内看到大量插入活动,那么这两个问题都只是一个问题。NEXT VALUE FOR The_sequence_You_DefinedSET @someVariable = NEXT VALUE FOR The_sequence_You_Defined;

一种更hacky 的方法可能是BIGINT为每个身份列使用一个,并以不同的倍数(例如)4,000,000,000 开始。这将适用于其他数据库并避免瓶颈问题,但会使您的密钥大小增加一倍,如果您不小心定义了两个 ID 开始于同一点的表,可能会给您带来维护噩梦。您可能希望添加检查约束以确保以这种方式定义的标识值不会溢出到另一个值的数字空间,这又增加了一些性能问题。

如果您不介意较大的键,那么UUID很有用,并且具有在数据库之间(所有数据库,顾名思义)而不仅仅是在一个数据库中的表之间唯一的额外优势。与序列一样,这些应用具有默认约束,即ID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT NEWID()。但是,这些是 128 位值,BITINT是“标准” 32 位的大小的两倍和四倍INTEGER。如果您担心由 v4 UUID 的随机性引起的额外碎片的可能性,您可以使用它NEWSEQUENTIALID()而不是NEWID()它应该仍然足够独特(在这个星系的生命周期中发生碰撞的可能性非常小)。