处理身份范围以进行事务复制


9

我注意到,当您设置事务复制时,SQL Server会将身份范围管理设置为手动。这意味着在我的订阅数据库中,当我尝试将新记录插入到其PK为标识列的表中时,它将给我一个错误,并说它试图插入PK为“ 1”,“ 2” ”,“ 3”等。这是因为订阅服务器上所有标识列的当前标识值都重置为种子值(通常为1),而不是停留在发布者上的原始值上。

我了解为什么SQL Server会这样做-您应该将订户表保留为只读状态。但是,我的情况有点不合常规-我不时通过复制更新订户,立即备份该数据库,然后我想对订户进行一些更新,以免将其推回发布者,然后当我再次更新订户时,我从较早的备份中还原了它的数据库并提取了最新的更新。因为我想在这些更新之间进行订阅服务器的更新(如果需要,可以使用“临时增量”),因此我需要Identity列起作用,并且复制时不要重置为1。

我尝试在设置发布时打开自动标识范围管理,但是当我尝试向发布中添加表时,这只会给我以下错误:

消息21231,级别16,状态1,过程sp_MSrepl_addarticle,第2243行
自动标识范围支持仅对允许更新订户的发布有用。

有什么办法可以解决这个问题?我确实想将此复制呈现给SQL Server,就好像它在订阅服务器端是只读的,因为我不打算进行将被推回发布服务器的更新,但是我确实想进行临时更新在下一次复制之前将被删除。

对于我的使用模式,我还认为快照复制可能比事务复制更合适,但是麻烦在于快照复制需要每个更新发送整个darn数据库。因为我打算在最新复制后立即备份数据库,所以我不需要每次都进行整个传输。只是自上次以来的变化。


您正在使用哪个版本的SQL Server?你能重新定义桌子吗?

2008年r2。我不知道重新定义表格会如何解决这个问题……
Jez

我当时在考虑使用SEQUENCE的解决方案,但这仅适用于

2
Is there any way I can get round this problem?对于SQL Server 2005及更高版本,必须使用sys.sp_identitycolumnforreplication将Identity列设置为NOT FOR REPLICATION。当您将标识列更改为非复制时,您甚至不必重新快照您的文章。只是不要使用GUI。
Kin Shah

它已被标记为不可复制。基本上这就是问题所在-SQL Server不会复制身份信息,因此在订阅服务器上,它是从1开始的
。– Jez

Answers:


3

假设您的发布者使用的是从1开始的int身份,则可以 DBCC CHECKIDENT('dbo.mytable', RESEED, -2147483648) 在订阅者处发布。然后,您可以使用-2147483648到0的范围来保存您的“临时增量”。


这是我想出的解决方案,但这仍然意味着我的代码连接到发布者和订阅者并手动同步身份。我希望有一种更自动的方法。
Jez

为什么需要手动同步身份?只需在订阅服务器上编写一个存储过程,该存储过程对要存储临时增量的每个表运行checkident,然后在快照完成应用后运行该存储过程。分发代理将在“真实”标识范围内发生更改时插入更改,而直接对订户进行的更改将在负范围内。
Liam Confrey

1

我最终要做的是坚持基于请求的事务复制,并让我的程序在同步后立即将订户标识值更新为与发布数据库上的相同(很高兴,我希望分发代理自行达成协议) )。用伪代码看起来像这样:

synchronize databases with TransSynchronizationAgent

equivalentTablesNotFound is a list of strings
for each table in publisher tables:
    try:
        check table identity value (this is via functionality provided by .NET's Microsoft.SqlServer.Management.Smo.Server class)
        parse identity value as integer to newIdentity
        if the table's identity value was NULL, skip to next loop iteration
        (HACK) increment newIdentity value by 1
        if there is no subscriber table with the same name as this one:
            record its name in equivalentTablesNotFound and skip to next loop iteration
        set subscriber table with same name's identity value to newIdentity using TSQL: DBCC CHECKIDENT ("tableName", newIdentity)
    catch:
        if exception shows that the error was because the table doesn't have an identity column, drop the exception

if equivalentTablesNotFound has more than zero entries, warn about tables on publisher without an equivalent name on subscriber

似乎工作正常。HACK位是因为,尽管默认情况下,并且对于我的所有表,标识值仅增加一,但是可以以不同的方式对其进行配置,因此从技术上讲,您应该在此处查找标识值如何在发布者表上递增并递增同样的方式。


0

我首选的处理方法是执行以下操作:

一个。首先停止您的复制代理(这样您就不会在订户数据库中获取任何新数据)

b。第二重命名您现有的表

exec sp_rename '[CurrentTable]', '[BackupTableName]'

C。用IDENTITY设置重新创建表

CREATE TABLE [CurrentTable]
(
   ID INT NOT NULL IDENTITY(1,1), 
   OtherField VARCHAR(10) NULL,
   ....
)

d。使用SET IDENTITY_INSERT回填表格(从[BackupTableName]中填充)

SET IDENTITY_INSERT [CurrentTable] ON
INSERT INTO [CurrentTable] (ID, OtherField, ...)
SELECT ID, OtherField, ....
FROM [BackupTableName]
SET IDENTITY_INSERT [CurrentTable] OFF

一旦你的身份对你的数据库的约束,那么你可以做自定义复制(即:改变你插入REPL PROC到SET IDENTITY_INSERT [表名] ON或者你可以设置NOT FOR桌子上复制标志(它告诉SQL服务器如果连接用户是复制代理,则希望提供IDENTITY值)(我更喜欢自定义复制方法,因为它为我提供了更大的灵活性

e。修改您的插入复制存储过程(通常命名为sp_MSins_CurrentTable)以也使用SET IDENTITY INSERT

ALTER procedure [dbo].[sp_MSins_CurrentTable]
    @c1 int, @c2 varchar(50), ...
as
begin
    /* allow replication to insert values for IDENTITY */
    SET IDENTITY_INSERT [CurrentTable] ON
    insert into [CurrentTable]
        ([ID], [OtherField], ...)
    values
        (@c1, @c2, ...)
    /* now turn off Identity insert */
    SET IDENTITY_INSERT [CurrentTable] OFF
end

F。现在,您可以重新启动复制代理。


1
大声笑,与使用相比DBCC CHECKIDENT,此方法需要大量工作。
Jez

@Jez,您需要重新创建表(使用IDENTITY)才能运行DBCC CHECKIDENT ...复制快照将创建没有IDENTITY约束的表(基于您的q我想说DBCC CHECKIDENT赢得了't work)
Andrew Bickerton

仅供参考,它确实起作用,并且复制确实创建了具有IDENTITY约束的表...
Jez

@Jez您设置了哪种复制类型?(如果将其设置为将要发生的MERGE,对于TRANSACTIONAL则通常不会,但是如果不使用GUI,则复制是高度可定制的)
Andrew Bickerton

交易性的。正如我所说的,IDENTITY在那里,但是当前的身份值被重置为种子值(1)。
耶斯(Jez)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.