合并复制如何计算已筛选发布中的分区

使用参数化筛选器和联接筛选器筛选合并发布中的一个或多个表后,已发布表中的数据将被分区。 “分区”只是表中的部分行。 订阅服务器与发布服务器同步时,发布服务器必须根据订阅服务器提供给系统函数 SUSER_SNAME() 和/或 HOST_NAME() 的值,确定哪些行属于订阅服务器的分区。 为接收已筛选数据集的每个订阅服务器确定发布服务器上更改的分区成员身份的过程称为“分区计算”。

根据已发布表中的数据以及创建参数化筛选器和任何相关的联接筛选器时选择的设置,已发布表中的每一行可以:

  • 属于一个分区并且只能复制到一个订阅服务器(sp_addmergearticle 的参数 @partition_options 的值为 3)。 例如,在 AdventureWorks2008R2 数据库中,可以使用下面的筛选子句筛选 Employee 表: WHERE Employee.LoginID = SUSER_SNAME()。与每个登录 ID 匹配的行只能发送到一个订阅服务器。

  • 属于一个分区并且可以复制到多个订阅服务器(@partition_options 的值为 2)。 例如,在 AdventureWorks2008R2 数据库中,可以使用下面的筛选子句筛选 Products 表: WHERE Products.ProductLine = HOST_NAME()。HOST_NAME() 值将被覆盖,以便负责销售山地自行车的销售人员组收到 ProductLine 列中的值为“M”的所有行;具有值“M”的每一行都只属于一个分区,但可以发送到多个订阅服务器。 有关使用 HOST_NAME() 的详细信息,请参阅 参数化行筛选器 中的“使用 HOST_NAME() 进行筛选”部分。

  • 属于多个分区并且复制到多个订阅服务器(@partition_options 的值为 01)。 例如,在 AdventureWorks2008R2 数据库中,可以使用下面的筛选子句筛选 Products 表: WHERE Products.ProductLine = HOST_NAME() or Products.ListPrice < 100。在这种情况下,只要售价低于 100 美元,负责销售山地自行车的销售人员就可以销售其他类别的产品。 因为筛选子句中有 OR,所以该行可以属于多个分区。

如何计算分区

合并复制中有两种计算分区的方式,具体采用哪一种取决于是否使用了预计算分区功能。 如果满足一些要求,则默认情况下使用启用的预计算分区创建新的合并发布,现有发布将自动升级以使用该功能。 有关全部要求,请参阅使用预计算分区优化参数化筛选器的性能

使用预计算分区计算分区

使用预计算分区时,预计算发布服务器上所有更改的分区成员身份,并在更改已发布表时保持该分区成员身份。 因此,当订阅服务器与发布服务器同步时,它可以立即开始下载与其分区相关的更改,而不必执行分区计算过程。 当发布中有大量更改、订阅服务器或项目时,这样可以显著提升性能。

预计算分区计算中涉及的系统表如下:

  • MSmerge_partition_groups

  • MSmerge_current_partition_mappings

  • MSmerge_past_partition_mappings

发布中定义的每个分区在 MSmerge_partition_groups 中都对应一行。 分区可以:

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

  • 在订阅服务器同步时自动创建(如果订阅服务器所要求的分区在 MSmerge_partition_groups 中尚没有相应的项)。

其他两个表(MSmerge_current_partition_mappingsMSmerge_past_partition_mappings)将在更改已发布表时填充。 每次更改发布数据库中的已发布表时,合并触发器都将激发并记录元数据:

  • 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 跟踪这些行的分区映射,因为每行只属于一个分区并且只能在一个订阅服务器上进行更改。

使用 SetupBelongs 进程计算分区

不使用预计算分区时,将使用一个称为 SetupBelongs 的进程。 在同步期间,对发布服务器上自上次为特定订阅服务器运行合并代理后已筛选表发生的每个更改执行分区计算。 对与发布服务器同步的每个订阅服务器重复此进程。

若要对订阅服务器执行分区计算,合并代理需要调用系统存储过程 sp_MSsetupbelongs,该存储过程:

  1. 为每个已筛选项目创建两个临时表: #belongs_<随机数>#notbelongs_<随机数>

  2. 在订阅服务器上使用 SUSER_SNAME() 函数和/或 HOST_NAME() 函数返回的值查询系统视图,该查询用于确定 MSmerge_contentsMSmerge_tombstone 中的某一行是否与订阅服务器的分区有关。

  3. 如果该行与订阅服务器完全无关(如其他分区的插入),则不将该行的元数据存储在 #belongs#notbelongs 中。 如果该行与订阅服务器有关,则有两种可能的结果:

    • 如果出现下列情况,则向 #belongs 中添加一行: MSmerge_contents 中的该行是该分区的一个插入,或者 MSmerge_contents 中的该行是一个更新,该更新不会更改用于筛选的任何列的值。

    • 如果出现下列情况,则向 #notbelongs 中添加一行: MSmerge_contents 中的该行是一个更新,该更新会更改用于筛选的任意列的值(即它将该行移到新分区),或者 MSmerge_tombstone 中的该行表示删除分区中的某行。

注意注意

即使启用了预计算分区,如果在其他订阅开始接收更改之后创建一个订阅,则在该订阅第一次同步时,仍将使用 SetupBelongs 进程。