合并复制如何跟踪和枚举更改

初始化发布或订阅后,合并复制将跟踪并枚举对已发布表中数据的所有更改。 通过触发器(复制为每个已发布的表创建)和发布和订阅数据库中的系统表跟踪更改。 这些复制系统表填充了元数据,这些元数据指示应传播哪些更改。 在同步过程中,“合并代理”运行时,代理会枚举变更,然后根据需要将其应用于发布服务器和订阅服务器。

更改跟踪

合并复制使用以下触发器和系统表来跟踪所有已发布表的更改:

  • MSmerge_ins_<GUID>:插入触发器(此触发器的 GUID 值和其他触发器派生自 sysmergearticles
  • MSmerge_upd_<GUID>:更新触发器
  • MSmerge_del_<GUID>:删除触发器
  • MSmerge_contents
  • MSmerge_tombstone
  • MSmerge_genhistory

合并复制使用以下额外的系统表来跟踪筛选表的更改:

  • MSmerge_partition_groups
  • MSmerge_current_partition_mappings
  • MSmerge_past_partition_mappings

注释

列出的系统表供数据库中的所有合并发布和订阅使用;例如,如果发布数据库中有多个发布,则 MSmerge_contents 包含所有发布中文章的项目。

更改未筛选表的跟踪

系统表

用于未筛选和筛选表的系统表包含以下元数据:

  • 对于数据库中已发布表中插入或更新的每一行,MSmerge_contents 都包含一行。

  • 对于从数据库中已发布表中删除的每一行,MSmerge_tombstone 都包含一行。

  • MSmerge_genhistory 包含一行对应于每一代。 一代是传递给发布者或订阅者的更改的集合。 每次运行合并代理时,代系都会被关闭;数据库的后续更改将添加到一个或多个开放代系中。

更改跟踪过程

以下更改跟踪过程用于所有未筛选的表:

  • 在已发布的表中发生插入或更新时,MSmerge_ins_<GUID>MSmerge_upd_<GUID> 触发器会触发,并将一行插入到 MSmerge_contents 系统表中。 MSmerge_contentsrowguid 列包含插入或更新的行的 GUID,表示下次发生同步时,用户表中相应的插入或更新行应发送给发布者或订阅者。 如果后续更新发生在用户表中的某一行上,则会更新该 MSmerge_contents 行以反映此状态。

  • 当对已发布的表进行删除时,MSmerge_del_<GUID> 触发器会触发,并将一行插入到 MSmerge_tombstone 系统表中。 MSmerge_tombstonerowguid 列包含删除的行的 GUID,表示下次发生同步时,应向用户表中相应已删除行的发布者或订阅者发送删除。 如果已删除的行在 MSmerge_contents 中被引用(因为自上次同步以来该行已被插入或更新),那么该行将从 MSmerge_contents 中删除。

更改已筛选表的跟踪

系统表

除了上一部分所述的系统表外,发布数据库中的三个表还包含用于跟踪筛选表更改的元数据:

  • MSmerge_partition_groups 包含发布中定义的每个分区的一行。 分区可以是:

    • 明确使用“发布属性”对话框的 sp_addmergepartition 或“数据分区”页面定义。

    • 如果订阅者需要的分区在 MSmerge_partition_groups 中还没有条目,则在订阅者同步时自动创建。

  • 对于 MSmerge_contentsMSmerge_partition_groups 中的每个唯一行组合,MSmerge_current_partition_mappings 都包含一行。 例如,如果用户表中的一行属于两个分区,并且该行已更新,则会插入 MSmerge_contents 一行以反映更新,并且插入两行 MSmerge_current_partition_mappings,以指示更新行属于这两个分区。

  • 对于不再属于给定分区的每一行,MSmerge_past_partition_mappings 都包含一行。 在下列情况下,将行移出分区:

    • 删除该行。 如果从用户表中删除一行,则会插入一行到MSmerge_tombstone,并插入一行或多行到MSmerge_past_partition_mappings

    • 用于筛选的列中的值已更改。 例如,如果参数化筛选器取决于公司总部所在的州,而公司搬迁了,那么关于该公司的行(以及其他表中的相关行)可能会从一个销售人员的数据分区转移到另一个销售人员的数据分区。 如果更新某一行以致其不再属于分区,则会在MSmerge_contents中插入或更新一行,并在MSmerge_past_partition_mappings中插入一行或多行。

注释

如果使用每个分区有一个订阅的非重叠分区(sp_addmergearticle@partition_options 参数的值为 3),则不使用系统表 MSmerge_current_partition_mappingsMSmerge_past_partition_mappings 来跟踪行的分区映射,因为每一行只属于一个分区,并且只能在一个订阅者上进行更改。

更改跟踪过程

前面介绍的过程(在 未筛选表的更改跟踪部分)还用于筛选表,并添加以下内容:

  • 在已发布的表中发生插入时,除了将数据更新或插入到 MSmerge_contents,还会为每个包含该行的分区在 MSmerge_current_partition_mappings 中添加分区映射。

  • 当在已发布的表上发生更新时,除了更新或插入到 MSmerge_contents 中的数据外,如果该行所属的每个分区的 MSmerge_current_partition_mappings 中不存在分区映射,则添加一个。 如果更新导致一行从一个分区移动到另一个分区,则在 MSmerge_current_partition_mappings 中会更新一行,并在 MSmerge_past_partition_mappings 中添加一行。

  • 当对已发布的表进行删除时,除了将一行插入到 MSmerge_tombstone 中外,还将从 MSmerge_current_partition_mappings 中删除一行,并将一行添加到 MSmerge_past_partition_mappings 中。

更改枚举

系统表和过程

合并代理运行时,使用多个系统表和存储过程枚举更改:

  • MSmerge_genhistory 包含一行对应于每一代。 一代是传递给发布者或订阅者的更改的集合。 每次运行合并代理时,代系都会被关闭;数据库的后续更改将添加到一个或多个开放代系中。

  • sysmergesubscriptions 包含有关订阅的信息,包括节点发送和接收的上一代更改记录。 在发布数据库中,此表包含用于发布者的一行和用于每个订阅者的一行。 在订阅数据库中,此表通常包含订阅方和发布方的一行。

  • MSmerge_generation_partition_mappings 仅用于筛选表,记录给定生成是否包含与给定分区相关的任何更改。 发布数据库中的此表包含一行,对应于 MSmerge_genhistoryMSmerge_partition_groups 中每一行的唯一组合。

  • sp_MSmakegeneration 在枚举过程开始时关闭所有打开的代。

  • sp_MSenumchanges 枚举表的更改(在此过程中还使用了几个名称以 sp_MSenumchanges 开头的相关过程)。

  • sp_MSgetmetadata 确定是否应将一个节点的更改作为插入、更新或删除应用于另一个节点。

更改枚举过程

在更改枚举过程中会发生以下过程:

  1. 系统过程 sp_MSmakegeneration 称为:

    • 对于未筛选的表和已筛选的表,此过程将关闭 MSmerge_genhistory 中引用的所有打开的代(关闭的代在列 genstatus 中的值为 12)。

    • 对于筛选表,此过程将填充系统表 MSmerge_generation_partition_mappings。 如果生成包含一个或多个与分区相关的更改,则会将一行插入到系统表中。 如果某个世代不包含与特定分区相关的任何更改,则不会在MSmerge_generation_partition_mappings中插入行,并且不会为接收该分区的任何订阅者枚举更改。

  2. 将调用存储过程 sp_MSenumchanges 和相关过程。 这些过程枚举自上次同步发生以来发生的更改:

    1. 过程首先根据表 sysmergesubscriptions 中列 sentgen(发送的最后一代)和 recgen(接收的最后一代)确定枚举开始的代。

      例如,在确定必须为给定订阅者枚举哪些代的更改时,将比较订阅者的 sentgen(存储在发布数据库中)和订阅者的 recgen(存储在订阅数据库中)。 如果值相同(这表明订阅者已成功接收到从发布者发送的最后一代),则从 MSmerge_genhistory 中的下一代开始枚举更改。 如果值不相同,则使用两个值的下限来确保发送所有必需的更改。

    2. 然后,程序列举更改:

      对于未筛选的表,枚举了 sentgenrecgen 中生成后的几代中包含的所有更改:MSmerge_genhistoryMSmerge_contentsMSmerge_tombstone 联接,以确定必须发送哪些更改。

      对于已筛选的表,MSmerge_generation_partition_mappings 联接到:MSmerge_current_partition_mappingsMSmerge_contents,以及 MSmerge_past_partition_mappingsMSmerge_tombstone,以确定哪些更改与订阅者接收的分区相关。

  3. 调用存储过程 sp_MSgetmetadata 以确定更改是否应作为插入、更新或删除应用。 此时,将执行冲突检测和解决;有关详细信息,请参阅 合并复制如何检测和解决冲突