Condividi tramite


合并复制无法使用Management Studio查看和解决冲突

合并复制无法使用Management Studio查看和解决冲突

在SQL Server中,我们提供了复制的功能以便多个SQL Server的实例能够共享数据。在复制的家族中,我们又提供了多种的选择。其中,如果多个SQL Server的实例需要共享修改时,我们需要使用合并复制。由于多个SQL Server实例能够修改相同的数据,导致数据修改的冲突,即不同的SQL Server实例修改在同步之前修改了相同的数据。在合并复制中,我们提供的一套完善的方法用来解决这个冲突问题。在自动的冲突检测和处理机制之后,冲突可以被用户手动根据需要查看和修改。

但是,在查看冲突的时候,用户可能会遇到如下的错误。

一般情况下,遇到这种错误要去解决是比较困难的。甚至需要检查Management Studio这个菜单的相关源码。但是,从这个错误本身来看,它是由于无法找到一个叫rowguid的列导致的。

对于这种错误,我们首先可以使用事件查探器(Profiler Trace)来查看是否有是Management Studio在View Conflicts中运行的语句产生的错误。我们可以使用时间查探器的列筛选功能使其只抓取Management Studio的语句。

当我们选择View Conflicts菜单项的时候,以上错误窗口就会被弹出。在点击Ok按钮后,相应的冲突查看窗口就会被显示。在事件查探器中,我们没有发现任何错误。在错误报告之前,如下的语句会被执行。(其中,test是出现冲突的表名)

sp_helpmergeconflictrows

sp_helpmergedeleteconflictrows

select *from [dbo].[test] where 1=2

select *, type_name(xtype) as datatype, (status & 0x80) as identitystatus from syscolumns where id = object_id('[dbo].[test]')

由此我们知道,这个错误并不是由于语句报错导致的。而是由于返回给Management Studio的相关结果集有一定的问题。即合并复制系统表中的数据存在一定的问题。

以下就是比较笨的方法了。我们将每个语句抓取出来,并再次在环境中运行。如果有运行良好的环境,我们可以将结果作一定的对比。这样能够迅速定位出现问题的语句。例如,在运行良好和有问题的环境中运行了sp_helpmergeconflictrows存储过程之后,我们发现问题环境返回的列少。而且,没有返回rowguid列。我们之后在合并复制中rowguid列被用来唯一标记一条数据。如果rowguid没有被返回,之后的一系列系统数据都可能不能被返回。

正常结果:

有问题结果:

我们之后可以使用sp_helptext查看sp_helpmergeconflictrows的内容。经过分析,我们知道这个存储过程会将冲突表(MSmerge_conflict_Test.Publicatication_test)和MSmerge_conflict_info做链接,并且返回相关的数据。具体语句如下,

select @colid = min(column_id) from sys.columns where object_id = object_id(@conflict_table)

 select @colname=name from sys.columns where object_id = object_id(@conflict_table) and column_id=@colid

 select @cmd = 'select '

 while (@colname is not NULL)

 begin

  if @colname <> 'origin_datasource_id'

  begin

   select @quotedcolname = quotename(@colname)

   select @cmd = @cmd + ' ct.' + @quotedcolname + ','

  end

  select @colid = min(column_id) from sys.columns where object_id = object_id(@conflict_table) and column_id > @colid

  select @colname = NULL

  select @colname=name from sys.columns where object_id = object_id(@conflict_table) and column_id=@colid

 end

    select @cmd = @cmd + ' m.origin_datasource, m.conflict_type, m.reason_code, m.reason_text, m.pubid, m.MSrepl_create_time from'

    select @cmd = @cmd + QUOTENAME(@conflict_table) + ' ct, MSmerge_conflicts_info m where ct.origin_datasource_id=m.origin_datasource_id

       and m.conflict_type<>4 and ct.rowguidcol=m.rowguid '

 

当我们将@conflict_table参数带入上段代码时,我们发现第一条语句就没有能够返回任何数据。经过思考,我们可以非常自信的得出结论。

select min(column_id) from sys.columns where object_id = object_id('MSmerge_conflict_Test.Publicatication_test')

冲突表的命名机制为MSmerge_conflict_<publication name>_<table name>。所以,我们可以得到这个有问题的环境中,发布的名字为Test.Publication。当创建和使用这个环境时,都不会有任何问题。但是,如果对这个要查看这个发布的冲突时,object_id()函数会将点(.)当作架构名(Schema Name)和表名(Table Name)之间的分隔符。所以,object_id()找不到一个架构名是Test并且表名是Publication的表,最后这个函数会返回NULL。从而导致rowguid列不能被返回及我们观察到的错误。

最后,我们的结论是,在合并复制中,不能在发布名中使用点(.)。否则会导致冲突查看功能不可用。总结我们在这个这种问题中的经验,我们可以将这种问题的解决步骤总结为,

1. 分析错误的可能原因

2. 抓取事件查探器日志,检查是否有语句报错。

3. 如果没有语句报错,逐条检查语句返回的结果是否有异常。

4. 如果发现返回结果异常,查看是否可以找出异常原因。

当然,如果这一切都还不能揭开迷雾。我们CSS数据库部门是您最好的选择。