发布服务器和订阅服务器上的数据不匹配

如果出现以下情况,则认为发布服务器和订阅服务器上的数据具有非收敛性(即数据不匹配):

  • 订阅服务器与发布服务器上的行数不同,并且发布未经筛选。如果发布已筛选,行数可能会有所不同。

  • 发布服务器和订阅服务器上的一行或多行数据的内容不同。

说明

发布服务器和订阅服务器上的数据可能由于以下若干原因具有非收敛性:

  • 订阅服务器本应被视为只读,但是其上的数据发生了更改。除非使用合并复制、具有可更新订阅的事务复制或对等事务复制,否则订阅数据库应被视为只读。

  • 在订阅服务器上使用了触发器。触发器可以修改订阅服务器上的数据,也可以在触发器发出 ROLLBACK 时防止更新这些数据。

  • 复制过程将在订阅服务器上执行脚本,但不会在发布服务器上执行脚本。

  • 对事务发布的存储过程执行的复制会在订阅服务器上产生不同的结果。

  • 违反约束或其他问题会导致无法在订阅服务器上插入、更新或删除行。

用户操作

下列操作描述了如何确定数据是否具有非收敛性以及如何使之具有收敛性:

  1. 通过使用验证或 tablediff 实用工具确定数据是否具有非收敛性:

    • 如果分发代理或合并代理能够运行,请通过运行二进制校验和验证来确定数据是否已丢失。还可以使用行计数验证,但是此方法无法显示数据内容的差异。有关详细信息,请参阅验证已复制的数据

    • 如果分发代理或合并代理不能运行,则可以运行 tablediff 实用工具来确定数据是否具有非收敛性。有关对复制表使用此实用工具的信息,请参阅如何比较所复制表的差异(复制编程)

  2. 如果数据具有非收敛性,可以使用 tablediff 实用工具生成 Transact-SQL 脚本以使数据具有收敛性。有关详细信息,请参阅 tablediff 实用工具

针对导致非收敛性的原因的措施

针对“说明”部分中列出的原因,可以采取下列操作:

  • 在复制之外的订阅服务器上更新数据:

    • 如果您希望允许用户在订阅服务器上插入、更新和删除数据,请使用合并复制、具有可更新订阅的事务复制或对等事务复制。有关详细信息,请参阅合并复制概述事务复制的发布类型

    • 如果希望防止用户在订阅服务器上插入、更新和删除数据,请为每个包含 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 来控制约束、标识和触发器

  • 在订阅服务器上使用了触发器。必须正确管理订阅服务器上的触发器,以便不会引起非收敛性问题或其他问题:

    • 如果使用合并复制、具有可更新订阅的事务复制、或对等事务复制,则触发器应只在订阅服务器上导致数据发生更改。有关详细信息,请参阅合并复制概述事务复制的发布类型

    • 在许多情况下,触发器应使用 NOT FOR REPLICATION 选项。例如有一个将数据插入到跟踪表中的触发器:当用户初始插入行时,将触发该触发器并在跟踪表中写入行,但在将数据复制到订阅服务器时,不应触发该触发器,因为这会导致在跟踪表中插入不必要的行。

      如果触发器包括 ROLLBACK 语句,并且不使用 NOT FOR REPLICATION 选项,则可能不会把行复制到订阅服务器。

    • 对于事务复制,还要注意有关 XACT_ABORT 设置以及在触发器中使用 COMMIT 和 ROLLBACK 语句的其他事项。有关详细信息,请参阅事务复制的注意事项的“触发器”部分。

  • 复制过程将在订阅服务器上执行脚本,但不会在发布服务器上执行脚本。

    使用 sp_addpublicationsp_addmergepublication@pre_snapshot_script@post_snapshot_script 参数,可以指定在应用快照之前和之后运行的脚本。有关详细信息,请参阅在应用快照之前和之后执行脚本。使用存储过程 sp_addscriptexec,您可以在同步过程中执行脚本。有关详细信息,请参阅如何在同步期间执行脚本(复制 Transact-SQL 编程)

    这些脚本通常用于管理任务。例如,在订阅服务器上添加登录名。如果用脚本来更新本应属于只读订阅服务器的数据,则管理员必须确保不会造成非收敛性。

  • 对事务发布的存储过程执行的复制会在订阅服务器上产生不同的结果。

    如果复制存储过程的执行,则在初始化订阅时,会将过程定义复制到订阅服务器;当在发布服务器上执行该过程时,复制将在订阅服务器上执行相应的过程。有关详细信息,请参阅在事务复制中发布存储过程执行

    如果存储过程在订阅服务器上执行的操作或作用的数据与发布服务器上的不同,则可能会产生非收敛性。请考虑使用执行计算的过程,然后基于此计算插入数据。如果对订阅服务器进行了筛选,导致订阅服务器上的计算基于不同的数据,则在订阅服务器上插入的结果可能不同,也可能根本就不插入数据。

  • 违反约束或其他问题会导致无法在订阅服务器上插入、更新或删除行。

    对于事务复制,违反约束将视为错误。默认情况下,如果遇到违反约束的情况,将会导致分发代理停止同步(有关跳过这些错误的信息,请参阅跳过事务复制中的错误)。对于合并复制,违反约束将视为冲突。会将其记入日志,但不会导致合并代理停止同步。对于这两种类型的复制,如果插入、更新或删除操作在一个节点上成功而在另一个节点上没有成功,则违反约束可能会导致无法收敛。

    在发布表时,如果设置了 NOT FOR REPLICATION 选项,则默认架构选项指定应在订阅数据库中创建外键约束和检查约束。如果应用程序需要不同的约束设置,请更改架构选项。有关详细信息,请参阅如何指定架构选项 (SQL Server Management Studio)如何指定架构选项(复制 Transact-SQL 编程)

请参阅

概念