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

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

更改跟踪

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

  • 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_current_partition_mappingsMSmerge_contentsMSmerge_partition_groups 中的行的每个唯一组合在此元数据中占一行。 例如,如果用户表中的某一行属于两个分区且对该行进行了更新,则向 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_genhistory 联接到 MSmerge_contentsMSmerge_tombstone 来确定必须发送哪些更改。

      对于已筛选的表,将 MSmerge_generation_partition_mappings 联接到: MSmerge_current_partition_mappingsMSmerge_contents;并联接到 MSmerge_past_partition_mappingsMSmerge_tombstone 来确定订阅服务器接收的与分区相关的更改。

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