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>
);
对于同一张表中的唯一 ID 值,我假设您知道常用的IDENTITY选项,通常使用从 1 开始的 32 位值(因此以这种方式定义 PK 类似于ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY)。BIGINT如果表可能需要超过 2,147,483,647 行,您当然可以使用更大的 ( )。
SQL Server 可以选择定义自己的序列,该序列可以在多个表之间共享,可能是所有表。有关详细信息,请参阅https://learn.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。不过,这里有一些事情需要注意。与IDENTITY您不同的是,不会阻止删除任何旧值(即不存在的值),因为默认情况下仅在未明确给出序列值时应用序列值,这可能是有问题的。此外,使用序列的执行速度会稍慢一些,并且可能会成为瓶颈,因为所有表都依赖于同一个对象,尽管这两个问题只有在您的数据库在短时间内看到大量插入活动时才会引起关注。NEXT VALUE FOR The_sequence_You_Defined也可以在其他地方使用(即SET @someVariable = NEXT VALUE FOR The_sequence_You_Defined;),这意味着如果您需要在应用程序逻辑的其他地方生成 ID,您可以通过这种方式完成(事实上,我已经看到它甚至用于单个身份,而不仅仅是共享序列多个对象之间)。
一个更 hacky 的方法可能是BIGINT对每个身份列使用 a,并从(例如)4,000,000,000 的不同倍数开始。这将在其他数据库中工作并避免瓶颈问题,但确实会使密钥大小增加一倍,并且如果您不小心定义了两个 ID 从同一点开始的表,则可能会给您带来维护噩梦。您可能希望添加检查约束以确保以这种方式定义的标识值不会溢出到另一个值的数字空间中,这会增加一些性能问题。
回到那天,我们有一张
ID
桌子。单列,单行,有一个int
值。每个事务首先更新该表以获得一个新值,然后在需要的地方使用该值。当然,这是并发错误的一个重要来源。后来,引入了序列。在整个数据库中使用的单个序列将显示您描述的行为。文档中有一个示例说明了这一点:
我编辑了示例以突出显示此用法。
通过在应用程序代码中生成全局唯一编号,然后将它们传递到数据库,可以获得相同的结果。如果我要实现它,我想它会作为编译到可执行文件中的某个实用程序类的静态方法(尽管其他实现是可能的)。假设应用程序需要将客户的详细信息写入数据库。由于它正在编组客户姓名、地址、电话号码等,它还会生成一个新的全局 ID。ID 仅作为另一个参数值传递给 INSERT 语句(或存储过程)。
ID 值是由应用程序架构层还是数据库层产生的,取决于具体的设计考虑。如果应用程序可以横向扩展实例之间的协调就会出现问题。应用程序重新启动后,代码必须找出下一个要使用的值。数据库服务器已经将这些功能和其他功能写入其中。
我绝对不会让应用程序只为下一个 ID 调用数据库,然后将其与业务数据一起编组到 INSERT 中。当只需要一次时,到数据库的往返次数太多了。
对于同一张表中的唯一 ID 值,我假设您知道常用的
IDENTITY
选项,通常使用从 1 开始的 32 位值(因此以这种方式定义 PK 类似于ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY
)。BIGINT
如果表可能需要超过 2,147,483,647 行,您当然可以使用更大的 ( )。SQL Server 可以选择定义自己的序列,该序列可以在多个表之间共享,可能是所有表。有关详细信息,请参阅https://learn.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
。不过,这里有一些事情需要注意。与IDENTITY
您不同的是,不会阻止删除任何旧值(即不存在的值),因为默认情况下仅在未明确给出序列值时应用序列值,这可能是有问题的。此外,使用序列的执行速度会稍慢一些,并且可能会成为瓶颈,因为所有表都依赖于同一个对象,尽管这两个问题只有在您的数据库在短时间内看到大量插入活动时才会引起关注。NEXT VALUE FOR The_sequence_You_Defined
也可以在其他地方使用(即SET @someVariable = NEXT VALUE FOR The_sequence_You_Defined;
),这意味着如果您需要在应用程序逻辑的其他地方生成 ID,您可以通过这种方式完成(事实上,我已经看到它甚至用于单个身份,而不仅仅是共享序列多个对象之间)。一个更 hacky 的方法可能是
BIGINT
对每个身份列使用 a,并从(例如)4,000,000,000 的不同倍数开始。这将在其他数据库中工作并避免瓶颈问题,但确实会使密钥大小增加一倍,并且如果您不小心定义了两个 ID 从同一点开始的表,则可能会给您带来维护噩梦。您可能希望添加检查约束以确保以这种方式定义的标识值不会溢出到另一个值的数字空间中,这会增加一些性能问题。如果您不介意较大的键,那么UUID很有用,并且具有在数据库(所有数据库,顾名思义)之间唯一的额外优势,而不仅仅是在一个数据库中的表之间。与序列一样,这些都与默认约束一起应用,即
ID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT NEWID()
. 不过,这些是 128 位值,BITINT
是“标准”32 位大小的两倍和四倍INTEGER
。如果您担心由 v4 UUID 的随机性引起的额外碎片的可能性,您可以使用它NEWSEQUENTIALID()
而不是NEWID()
仍然足够独特(在这个星系的生命周期中发生碰撞的机会非常小)。首先,我不得不提一下,我没有使用 SQL Server,所以我不能指出一些具体的功能。
我有两个关于如何做到这一点的概念:
在 SQL Server 世界中,您可以参考: NEWID() 文档- newid 符合RFC4122