当前未向订阅服务器传递数据
如果当前似乎未向订阅服务器传递数据,主要有两大原因:
由于筛选、某种代理问题或其他复制错误,当前未应用数据。
应用数据后,正在订阅服务器上将其删除。
说明
有多种原因可能会导致当前未向订阅服务器传递数据:
表已经过筛选,没有要传递到指定订阅服务器的更改。
代理未运行或由于错误导致失败。
事务订阅初始化未使用快照,并且创建发布后发布服务器上出现了更改。
对事务发布的存储过程执行的复制会在订阅服务器上产生不同的结果。
事务项目使用的 INSERT 存储过程中包含一个未满足的条件。
数据被用户、复制脚本或其他应用程序删除。
数据被触发器删除,或者触发器包含 ROLLBACK 语句。
用户操作
在试图诊断当前未向订阅服务器传递数据的原因之前,我们建议用验证实用工具或 tablediff 实用工具验证是否缺行:
如果分发代理或合并代理能够运行,请通过运行二进制校验和验证来确定数据是否已丢失。还可以使用行计数验证,但是此方法无法显示数据内容的差异。有关详细信息,请参阅验证已复制的数据。
如果分发代理或合并代理无法运行,则可以运行 tablediff 实用工具来确定是否缺少数据。有关对复制表使用此实用工具的信息,请参阅如何比较所复制表的差异(复制编程)。
找出缺少数据的原因
针对“说明”部分中列出的原因,可以采取下列操作:
表已经过筛选,没有要传递到指定订阅服务器的更改。
未复制订阅服务器上缺少的行可能是因为它们不符合发布的筛选条件。所有类型的复制都支持静态筛选,而合并复制还支持参数化筛选器和联接筛选器。有关详细信息,请参阅筛选已发布数据。如果要筛选发布中的项目,请执行下列过程,并验证筛选子句的值:
快照和事务发布的静态筛选:sp_helparticle (Transact-SQL) 返回的 filter_clause 列。
合并发布的静态筛选器或参数化筛选器:sp_helpmergearticle (Transact-SQL) 返回的 subset_filterclause 列。
合并发布的联接筛选器:sp_helpmergefilter (Transact-SQL) 返回的 join_filterclause 列。
用筛选子句确定是否某些缺少的行符合筛选条件。例如,可以对发布服务器上的表执行筛选子句并确定返回的数据是否与订阅服务器上的数据匹配。
代理未运行或由于错误导致失败:
如果正在初始化订阅,请确保在尝试使用分发代理或合并代理应用快照之前,要发布的快照代理已完成。如果试图在快照完成前应用它,会出现下列错误:“发布 '%s' 的初始快照尚不可用。”
对于事务复制,请确保分发代理和日志读取器代理正在运行。对于合并复制,请确保合并代理正在运行。有关启动这些代理的信息,请参阅如何启动和停止复制代理 (SQL Server Management Studio) 和复制代理可执行文件概念。
如果代理由于出错导致停止,请查看代理的错误详细信息,确定出错的根本原因。有关如何查看快照代理和日志读取器代理的错误详细信息的信息,请参阅如何查看与发布相关的代理的信息并执行此代理的任务(复制监视器)。有关分发代理和合并代理的信息,请参阅如何查看与订阅相关的代理的信息并执行此代理的任务(复制监视器)。如果错误继续出现,请增加代理的日志记录并指定日志的输出文件。此操作可能会提供找到该错误和/或其他错误消息的步骤,具体取决于错误的上下文。有关详细信息,请参阅复制代理(故障排除)。
导致数据无法传递的常见错误有权限问题和违反约束。有关权限问题的详细信息,请参阅安全问题正在阻止复制数据。违反约束会导致无法在订阅服务器上插入行。
对于事务复制,违反约束将视为错误。默认情况下,如果遇到违反约束的情况,将会导致分发代理停止同步(有关跳过这些错误的信息,请参阅跳过事务复制中的错误)。对于合并复制,违反约束将视为冲突。会将其记入日志,但不会导致合并代理停止同步。对于这两种类型的复制,如果插入、更新或删除操作在一个节点上成功而在另一个节点上没有成功,则违反约束可能会导致无法收敛。
在发布表时,如果设置了 NOT FOR REPLICATION 选项,则默认架构选项指定应在订阅数据库中创建外键约束和检查约束。如果应用程序需要不同的约束设置,请更改架构选项。有关详细信息,请参阅如何指定架构选项 (SQL Server Management Studio) 和如何指定架构选项(复制 Transact-SQL 编程)。
事务订阅初始化未使用快照,并且创建发布后发布服务器上出现了更改:
如果让发布能够从备份中初始化,则一旦创建了发布,就会在发布数据库日志中跟踪对已发布表的更改。初始化订阅时,只要挂起的更改仍可用于分发数据库,就会将它们传递至订阅服务器。
与从备份中初始化不同,如果使用“仅支持复制”选项初始化订阅,则您或您的应用程序就必须确保在添加订阅时正确同步数据和架构。例如,如果从将数据和架构复制到订阅服务器到添加订阅这一时间段内,发布服务器上进行了某一活动,则此活动导致的更改可能不会复制到订阅服务器。
有关详细信息,请参阅初始化事务订阅(不使用快照)。
对事务发布的存储过程执行的复制会在订阅服务器上产生不同的结果。
如果复制存储过程的执行,则在初始化订阅时,会将过程定义复制到订阅服务器;当在发布服务器上执行该过程时,复制将在订阅服务器上执行相应的过程。有关详细信息,请参阅在事务复制中发布存储过程执行。
如果存储过程在订阅服务器上执行的操作或作用的数据与发布服务器上的不同,则可能会产生非收敛性。请考虑使用执行计算的过程,然后基于此计算插入数据。如果对订阅服务器进行了筛选,导致订阅服务器上的计算基于不同的数据,则在订阅服务器上插入的结果可能不同,也可能根本就不插入数据。
事务项目使用的 INSERT 存储过程中包含一个未满足的条件。
默认情况下,事务复制用一组存储过程将更改传播至订阅服务器。您也可以自定义这些过程,以将您的应用程序所需的业务逻辑包括在内。有关详细信息,请参阅指定如何传播事务性项目的更改。如果 INSERT 存储过程在它的逻辑中包含一个未满足的条件,则不进行插入。假设有一个定制的存储过程先检查订阅服务器上某个表(表 A)中的特定值,然后才允许插入到另一表(表 B)。如果由于错误或由于数据未复制到表 A 而导致表 A 中没有该值,那么表 B 中就会缺少这个本该有的行。
数据被用户、复制脚本或其他应用程序删除:
如果您希望允许用户在订阅服务器上删除数据,请使用合并复制、具有可更新订阅的事务复制或对等事务复制。删除会传播到发布服务器,所以,发布服务器和订阅服务器上的数据最终会收敛。有关详细信息,请参阅合并复制概述和事务复制的发布类型。
如果希望防止用户在订阅服务器上删除数据,请为每个包含 ROLLBACK 词语并使用 NOT FOR REPLICATION 选项(此选项阻止触发器在复制代理执行操作时触发)的表创建一个触发器。例如:
USE AdventureWorks2008R2; GO CREATE TRIGGER prevent_user_dml ON Person.Address FOR INSERT, UPDATE, DELETE NOT FOR REPLICATION AS ROLLBACK;
有关详细信息,请参阅 CREATE TRIGGER (Transact-SQL) 和使用 NOT FOR REPLICATION 来控制约束、标识和触发器。
复制允许您在应用快照前后以及在同步期间执行脚本。使用 sp_addpublication 和 sp_addmergepublication 的 @pre_snapshot_script 和 @post_snapshot_script 参数,可以指定在应用快照之前和之后运行的脚本。有关详细信息,请参阅在应用快照之前和之后执行脚本。使用存储过程 sp_addscriptexec,您可以在同步过程中执行脚本。有关详细信息,请参阅如何在同步期间执行脚本(复制 Transact-SQL 编程)。
这些脚本通常用于管理任务。例如,在订阅服务器上添加登录名。如果用脚本来删除本应属于只读订阅服务器的数据,则管理员必须确保不会造成非收敛性。
数据正由触发器删除,或者触发器包含 ROLLBACK 语句。
必须正确管理订阅服务器上的触发器,以便不会引起非收敛性问题或其他问题: