在发布订阅中增加rowversion数据类型字段引发错误(or bug)
2011-12-01 13:19
471 查看
考虑这样的场景,现在每天要同步更新的数据,为了记录哪些数据发生过变更,需要对表添加一个rowversion列来标识被更新过。恰好这个表比较大,而且有发布订阅。由于该字段对于订阅表来讲,无实际意义,而且添加一个有默认值的不可为空的8字节字段,会产生数据空间分配,或许带来大量的页拆分,对IO压力会加大,所以考虑将此表的发布项暂时改为不支持架构复制,等添加完该字段后,再将其改为支持架构复制。
下面来做这个测试:
1.下面是一个正常的事务发布,将DB_1中的T_1发布到DB_2的T_1表中。
2.修改发布项DBrepTEST关于架构复制的选项,设置为不支持
3.然后,添加一个字段,类型为rowversion
4.经过观察,发布订阅一切正常,该字段并未被创建在订阅库DB_2上
5.我们在另外一个进程开始一个sql,向表DB_1.dbo.T_1 insert data.
6.发现数据已同步到DB_2.dbo.T_1,但rv字段并未被同步,现在一切正常
7.现在将发布项DBrepTEST修改回支持架构复制
8.然后,此时向表DB_1.dbo.T_1新加一个int类型字段
9.此时发布订阅出错
出错文字为:
Command attempted:
if @@trancount > 0 rollback tran
(Transaction sequence number: 0x000000580000013C000100000000, Command ID: 6)
Error messages:
A DDL change has been replicated. (Source: MSSQL_REPL, Error number: MSSQL_REPL27332)
Get help: http://help/MSSQL_REPL27332 列名 'rv' 无效。 (Source: MSSQLServer, Error number: 207)
Get help: http://help/207 10.由上面的信息,可以看出此时是由于在订阅库上找不到rv这个列造成的,为了确定这一点,我们看下这个事务执行的是什么
11.由10的结果中的command列,得到如下需要应用到订阅库的t-sql
可以看到对于添加字段,会重新创建对表操作的三个proc,本例中,insert这个proc会将rv加入进来,并且值为default,如下所示,但由于该列并不存在于订阅中,所以就会报错了,由此造成分发中断,后续事务无法应用到订阅端。
12.虽然可以通过在订阅端手工端建一个rv列,将其设置为可为null的varbinary(8)类型,但这个列对于订阅并没有实际意义。
总结,经过测试,发现当添加其它类型字段,并设置为有默认值且not null时,不会有此错误出现,目前发现仅是rowversion类型列,不知是否为SQL Server bug.
测试环境:windows server 2003 enterprise 32bit sql server 2008 sp2 standard 32bit
下面来做这个测试:
1.下面是一个正常的事务发布,将DB_1中的T_1发布到DB_2的T_1表中。
2.修改发布项DBrepTEST关于架构复制的选项,设置为不支持
DECLARE @publication AS sysname SET @publication = N'DBrepTEST' USE DB_1 EXEC sp_changepublication @publication = @publication, @property = N'replicate_ddl', @value = 0 GO
3.然后,添加一个字段,类型为rowversion
use DB_1 alter table t_1 add rv rowversion
4.经过观察,发布订阅一切正常,该字段并未被创建在订阅库DB_2上
5.我们在另外一个进程开始一个sql,向表DB_1.dbo.T_1 insert data.
while 1=1 begin waitfor delay '00:00:01' insert into DB_1.dbo.T_1(name)select 'a' end
6.发现数据已同步到DB_2.dbo.T_1,但rv字段并未被同步,现在一切正常
7.现在将发布项DBrepTEST修改回支持架构复制
DECLARE @publication AS sysname SET @publication = N'DBrepTEST' USE DB_1 EXEC sp_changepublication @publication = @publication, @property = N'replicate_ddl', @value = 1 GO
8.然后,此时向表DB_1.dbo.T_1新加一个int类型字段
use DB_1 go alter table t_1 add age int
9.此时发布订阅出错
出错文字为:
Command attempted:
if @@trancount > 0 rollback tran
(Transaction sequence number: 0x000000580000013C000100000000, Command ID: 6)
Error messages:
A DDL change has been replicated. (Source: MSSQL_REPL, Error number: MSSQL_REPL27332)
Get help: http://help/MSSQL_REPL27332 列名 'rv' 无效。 (Source: MSSQLServer, Error number: 207)
Get help: http://help/207 10.由上面的信息,可以看出此时是由于在订阅库上找不到rv这个列造成的,为了确定这一点,我们看下这个事务执行的是什么
use distribution go EXEC sp_browsereplcmds '0x000000580000013C000100000000','0x000000580000013C000100000000'
11.由10的结果中的command列,得到如下需要应用到订阅库的t-sql
ALTER TABLE [dbo].[T_1] add age int if object_id(N'[dbo].[sp_MSins_dboT_1]', 'P') > 0 drop proc [dbo].[sp_MSins_dboT_1] -- if object_id(N'dbo.MSreplication_objects') is not null delete from dbo.MSreplication_objects where object_name = N'sp_MSins_dboT_1' -- create procedure [dbo].[sp_MSins_dboT_1] @c1 int, @c2 varchar(20), @c3 int as begin insert into [dbo].[T_1]( [id], [name], [rv], [age] ) values ( @c1, @c2, default, @c3 ) end -- if columnproperty(object_id(N'dbo.MSreplication_objects'), N'article', 'AllowsNull') is not null exec sp_executesql @statement = N'insert dbo.MSreplication_objects (object_name, publisher, publisher_db, publication, article, object_type) values (@object_name, @publisher, @publisher_db, @publication, @article, ''P'')', @parameters = N'@object_name sysname, @publisher sysname, @publisher_db sysname, @publication sysname, @article sysname', @object_n ame = N'sp_MSins_dboT_1', @publisher = N'mySrv\SQL2008', @publisher_db = N'DB_1', @publication = N'DBrepTEST', @article = N'T_1' -- -- if object_id(N'[dbo].[sp_MSdel_dboT_1]', 'P') > 0 drop proc [dbo].[sp_MSdel_dboT_1] -- if object_id(N'dbo.MSreplication_objects') is not null delete from dbo.MSreplication_objects where object_name = N'sp_MSdel_dboT_1' -- create procedure [dbo].[sp_MSdel_dboT_1] @pkc1 int as begin delete [dbo].[T_1] where [id] = @pkc1 if @@rowcount = 0 if @@microsoftversion>0x07320000 exec sp_MSreplraiserror 20598 end -- if columnproperty(object_id(N'dbo.MSreplication_objects'), N'article', 'AllowsNull') is not null exec sp_executesql @statement = N'insert dbo.MSreplication_objects (object_name, publisher, publisher_db, publication, article, object_type) values (@object_name, @publisher, @publisher_db, @publication, @article, ''P'')', @parameters = N'@object_name sysname, @publisher sysname, @publisher_db sysname, @publication sysname, @article sysname', @object_n ame = N'sp_MSdel_dboT_1', @publisher = N'mySrv\SQL2008', @publisher_db = N'DB_1', @publication = N'DBrepTEST', @article = N'T_1' -- -- if object_id(N'[dbo].[sp_MSupd_dboT_1]', 'P') > 0 drop proc [dbo].[sp_MSupd_dboT_1] -- if object_id(N'dbo.MSreplication_objects') is not null delete from dbo.MSreplication_objects where object_name = N'sp_MSupd_dboT_1' -- create procedure [dbo].[sp_MSupd_dboT_1] @c1 int = NULL, @c2 varchar(20) = NULL, @c3 int = NULL, @pkc1 int = NULL, @bitmap binary(1) as begin update [dbo].[T_1] set [name] = case substring(@bitmap,1,1) & 2 when 2 then @c2 else [name] end, [age] = case substring(@bitmap,1,1) & 4 when 4 then @c3 else [age] end where [id] = @pkc1 if @@rowcount = 0 if @@microsoftversion>0x07320000 exec sp_MSreplraiserror 20598 end -- if columnproperty(object_id(N'dbo.MSreplication_objects'), N'article', 'AllowsNull') is not null exec sp_executesql @statement = N'insert dbo.MSreplication_objects (object_name, publisher, publisher_db, publication, article, object_type) values (@object_name, @publisher, @publisher_db, @publication, @article, ''P'')', @parameters = N'@object_name sysname, @publisher sysname, @publisher_db sysname, @publication sysname, @article sysname', @object_n ame = N'sp_MSupd_dboT_1', @publisher = N'mySrv\SQL2008', @publisher_db = N'DB_1', @publication = N'DBrepTEST', @article = N'T_1' -- --
可以看到对于添加字段,会重新创建对表操作的三个proc,本例中,insert这个proc会将rv加入进来,并且值为default,如下所示,但由于该列并不存在于订阅中,所以就会报错了,由此造成分发中断,后续事务无法应用到订阅端。
create procedure [dbo].[sp_MSins_dboT_1] @c1 int, @c2 varchar(20), @c3 int as begin insert into [dbo].[T_1]( [id], [name], [rv], [age] ) values ( @c1, @c2, default, @c3 )
12.虽然可以通过在订阅端手工端建一个rv列,将其设置为可为null的varbinary(8)类型,但这个列对于订阅并没有实际意义。
use DB_2 go alter table t_1 add rv varbinary(8)
总结,经过测试,发现当添加其它类型字段,并设置为有默认值且not null时,不会有此错误出现,目前发现仅是rowversion类型列,不知是否为SQL Server bug.
测试环境:windows server 2003 enterprise 32bit sql server 2008 sp2 standard 32bit
相关文章推荐
- SQL 2012 发布与订阅实现数据同步 图解(解决 错误22022)
- 发布NBearLite v1.0.0: 提供强类型查询语法的非ORM数据访问组件 [8/2 更新至v1.0.0.9 beta - 修复NBearLite参考手册某些操作系统打开错误的问题]
- 向ACCESS中的"时间/日期"字段中插入DateTime.Now时出现“标准表达式中数据类型不匹配。”错误的解决办法
- 学点 C 语言(17): 数据类型 - 因类型引发的问题或错误
- SQL Server2008修改数据表字段类型保存提示错误
- mysql命令行命令和SQL语句,MySQL修改删除增加字段类型,字段数据等。。
- mogoose的bug之不能根据类型为number的字段查找数据
- 向ACCESS中的"时间/日期"字段中插入DateTime.Now时出现“标准表达式中数据类型不匹配。”错误的解决办法
- SQL 2012 发布与订阅实现数据同步 图解(解决 错误22022)
- SQL 2012 发布与订阅实现数据同步 图解(解决 错误22022)
- 订单号数据类型修改--删除和创建复制订阅项目(只需要操作指定字段作为主键的那些)
- 格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://tempuri.org/ 进行反序列化时出错: GetLzdtArticleResult。InnerException 消息是“反序列化对象 属于类型 lzdt.DTO.Dtolzdt[] 时出现错误。读取 XML 数据时,超出最大
- SqlServer 禁止架构更改的复制中手动修复使发布和订阅中分别增加的字段同步
- C#发布程序时出现Signtool requires CAPICOM version 2.1.0.1 or higher错误的解决办法
- 发布NBearLite v1.0.0: 提供强类型查询语法的非ORM数据访问组件 [8/2 更新至v1.0.0.9 beta - 修复NBearLite参考手册某些操作系统打开错误的问题]
- 数据类型强制转换引发的一些意想不到的错误
- C#发布程序时出现Signtool requires CAPICOM version 2.1.0.1 or higher错误的解决办法
- SQLServer 可更新订阅数据在线架构更改(增加字段)方案
- 发布NBearLite v1.0.0: 提供强类型查询语法的非ORM数据访问组件 [8/2 更新至v1.0.0.9 beta - 修复NBearLite参考手册某些操作系统打开错误的问题]
- 更新数据库所有表的某一个指定字段 ,附加对‘将 varchar 值转换为数据类型为 int 的列时发生语法错误’处理方法