向列分配 IDENTITY 属性时,Microsoft SQL Server 会自动为包含标识列的表中插入的新行生成顺序号。 有关详细信息,请参阅 IDENTITY (属性) (Transact-SQL)。 由于标识列可能作为主键的一部分包含在内,因此请务必避免标识列中的重复值。 若要在复制拓扑中使用具有多个节点更新的标识列,复制拓扑中的每个节点都必须使用不同的标识值范围,以便不会发生重复项。
例如,可以为发布服务器分配范围 1-100、订阅服务器 A 范围 101-200 和订阅服务器 B 范围 201-300。 如果在发布者上插入了一行,并且标识值为 65,则该值将复制到每个订阅者。 复制在每个订阅服务器上插入数据时,它不会递增订阅服务器表中的标识列值;而是插入文本值 65。 只有用户插入,但不是复制代理插入会导致标识列值递增。
复制可跨所有发布和订阅类型处理标识列,使你可以手动管理这些列或让复制自动管理这些列。
注释
不支持向已发布表中添加身份列,因为当身份列复制到订阅者时,可能导致不收敛。 Publisher 的标识列中的值取决于受影响表的行以物理方式存储的顺序。 行可能以不同的方式存储在订阅服务器上;因此,同一行的标识列的值可能不同。
指定身份范围管理选项
复制提供三个标识范围管理选项:
自动。 用于合并复制和事务复制以及订阅服务器上的更新。 指定发布服务器和订阅服务器的大小范围,复制会自动管理新范围的分配。 复制设置订阅服务器上的标识列上的 NOT FOR REPLICATION 选项,以便只有用户插入会导致值在订阅服务器上递增。
注释
订阅者必须与发布者同步才能接收新范围。 由于订阅服务器会自动分配标识范围,因此,如果订阅服务器重复请求新范围,则任何订阅服务器都可能会耗尽整个标识范围的供应。
手动。 用于快照和事务复制,而无需在订阅服务器上进行更新、对等事务复制,或者应用程序必须以编程方式控制标识范围。 如果指定手动管理,则必须确保将范围分配给发布服务器和每个订阅服务器,并在使用初始范围时分配新范围。 复制在订阅服务器上的标识列设置了“NOT FOR REPLICATION”选项。
没有。 仅建议使用此选项来实现与早期版本 SQL Server 的向后兼容性,并且仅通过存储过程接口用于事务性发布。
若要指定标识范围管理选项,请参阅 “管理标识列”。
分配身份范围
合并复制和事务复制使用不同的方法来分配范围;本部分介绍了这些方法。
复制标识列时,需要考虑两种类型的范围:分配给发布服务器和订阅服务器的范围以及列中数据类型的范围。 下表显示了通常用于标识列中的数据类型的范围。 该范围用于拓扑中的所有节点。 例如,如果使用 smallint 从 1 开始并以 1 递增,则发布者和所有订阅者的最大插入数为三万二千七百六十七。 实际插入次数取决于所使用的值是否存在差距,以及是否使用了阈值。 有关阈值的详细信息,请参阅以下部分“合并复制”和“使用排队更新订阅的事务复制”。
如果在插入后发布者耗尽标识范围,而插入是由 db_owner 固定数据库角色的成员执行的,则可以自动分配一个新范围。 如果插入由不在该角色中的用户执行,则日志读取器代理、合并代理或属于 db_owner 角色成员的用户必须运行 sp_adjustpublisheridentityrange(Transact-SQL)。 对于事务发布,日志读取器代理必须运行才能自动分配新范围(默认是代理要连续运行)。
警告
在批量插入操作过程中,复制触发器只触发一次,而不是对每一行进行触发。 如果在大规模插入(如 INSERT INTO 语句)期间耗尽标识范围,可能导致 insert 语句失败。
| 数据类型 | 范围 |
|---|---|
tinyint |
不支持自动管理 |
smallint |
-2^15 (-32,768) 到 2^15-1 (32,767) |
int |
-2^31 (-2,147,483,648) 到 2^31-1 (2,147,483,647) |
bigint |
-2^63 (-9,223,372,036,854,775,808) 到 2^63-1 (9,223,372,036,854,775,807) |
decimal 和 numeric |
-10^38+1 到 10^38-1 |
注释
若要创建可在多个表中使用的自动递增数字,或者在不引用任何表的情况下从应用程序调用的数字,请参阅 序列号。
合并复制
标识范围由发布服务器管理,由合并代理传播到订阅服务器(在重新发布层次结构中,范围由根发布服务器和重新发布者管理)。 标识值是从发布者的资源池中分配的。 在“新建发布向导”中或使用 sp_addmergearticle(Transact-SQL)将具有标识列的项目添加到发布时,请指定以下项的值:
@identity_range参数用于控制标识范围的大小,此范围最初分配给发布者以及拥有客户端订阅的订阅者。
注释
对于运行以前版本的 SQL Server 的订阅服务器,此参数(而不是 @pub_identity_range 参数)还控制重新发布订阅服务器的标识范围大小。
@pub_identity_range参数,用于控制分配给具有服务器订阅的订阅者的标识范围大小(重新发布数据所需)。 所有拥有服务器订阅的用户都会收到一组用于重新发布的数据,即使他们实际上并没有重新发布数据。
@threshold参数,用于确定订阅 SQL Server Compact 或早期版本的 SQL Server 是否需要新的标识范围。
例如,可以为 @identity_range 指定 10000, @pub_identity_range指定 500000。 发布服务器和运行 SQL Server 2005 或更高版本的所有订阅服务器(包括具有服务器订阅的订阅服务器)分配的主要范围为 10000。 为具有服务器订阅的订阅服务器分配了主范围 500000,订阅服务器可与重新发布订阅服务器同步使用(还必须在重新发布订阅服务器上为发布中的项目指定 @identity_range、 @pub_identity_range和 @threshold )。
运行 SQL Server 2005 或更高版本的每个订阅者也会接收辅助标识范围。 次要区域的大小等于主要范围;当主范围用尽时,将使用辅助范围,合并代理会将新范围分配给订阅服务器。 新范围将成为辅助范围,并且当订阅方使用标识符值时,该过程将继续。
具有排队更新订阅的事务复制
标识范围由分发服务器管理,分发代理传播到订阅服务器。 标识值是从分发服务器的池分配的。 基于数据类型大小和标识列所使用的增量来确定池的大小。 在“新建发布向导”中或使用 sp_addarticle(Transact-SQL)将具有标识列的文章添加到发布时,请指定以下内容的值:
@identity_range参数,用于控制最初分配给所有订阅服务器的标识范围大小。
@pub_identity_range参数,用于控制分配给发布服务器的标识范围大小。
@threshold参数,用于确定订阅是否需要新的标识范围。
例如,可以为 @pub_identity_range指定 10000,为 @identity_range指定 1000(假设订阅服务器上的更新较少),@threshold的阈值为 80%。 在订阅者处插入 800 次(1000 的 80%)之后,订阅者将被分配一个新范围。 在发布者插入 8000 次后,发布者将被分配一个新范围。 分配新范围时,表中的标识范围值将存在差距。 指定更高的阈值会导致较小的差距,但系统容错程度较低:如果分发代理因某种原因无法运行,订阅者可能更容易耗尽身份标识。
为手动管理身份范围分配范围
如果指定手动标识范围管理,则必须确保发布服务器和每个订阅服务器使用不同的标识范围。 例如,考虑发布服务器上的表,其标识列定义为 IDENTITY(1,1):标识列从 1 开始,每次插入行时递增 1。 如果发布者的表有 5,000 行,并且预计在应用程序生命周期内表会有所增长,则发布者可以使用 1 到 10,000 的范围。 给定两个订阅服务器,订阅服务器 A 可以使用 10,001-20,000,订阅服务器 B 可以使用 20,001-30,000。
在用快照或其他方式初始化订阅者后,执行 DBCC CHECKIDENT 以为订阅者的标识范围分配一个起始点。 例如,在用户 A 处,将执行 DBCC CHECKIDENT('<TableName>','reseed',10001)。 在订阅服务器 B 中,将执行 CHECKIDENT('<TableName>','reseed',20001)。
若要将新范围分配给发布服务器或订阅服务器,请执行 DBCC CHECKIDENT 并指定要重新分配表的新值。 应该有一些方法来确定何时必须分配新范围。 例如,应用程序可以具有一种机制,用于检测节点何时即将使用其范围并使用 DBCC CHECKIDENT 分配新范围。 还可以添加检查约束,以确保如果行会导致使用范围外标识值,则无法添加该行。
在数据库还原后管理标识范围
如果使用自动标识范围管理,则从备份还原订阅服务器时,它会自动请求新的标识值范围。 如果发布服务器是从备份还原的,则必须确保为发布服务器分配适当的范围。 对于合并复制,请使用 sp_restoremergeidentityrange(Transact-SQL)分配新范围。 对于事务复制,请确定已使用的最高值,然后为新范围设置起点。 还原发布数据库后,请使用以下过程:
停止所有订阅服务器上的所有活动。
对于包含标识列的每个已发布表:
在每个订阅服务器上的订阅数据库中,执行
IDENT_CURRENT('<TableName>')。记录在所有订阅者中找到的最高值。
在 Publisher 中的发布数据库中,执行
DBCC CHECKIDENT(<TableName>','reseed',<HighestValueFound+1>。在发布服务器上的发布数据库中,执行
sp_adjustpublisheridentityrange <PublicationName>, <TableName>。
注释
如果标识列中的值设置为递减而不是递增,请记录找到的最小值,然后使用该值重新分配。
另请参阅
BACKUP (Transact-SQL)
DBCC CHECKIDENT (Transact-SQL)
IDENT_CURRENT(Transact-SQL)
IDENTITY(属性)(Transact-SQL)
sp_adjustpublisheridentityrange(Transact-SQL)