如何定义合并表项目之间的逻辑记录关系(复制 Transact-SQL 编程)

注意注意

后续版本的 Microsoft SQL Server 将删除该功能。 请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。

您可以使用合并复制来定义不同表中相关行之间的关系。也就是说,在同步期间可将行作为事务单元进行处理。无论两个项目之间是否存在联接筛选器关系,都可以在这两个项目之间定义逻辑记录。有关详细信息,请参阅通过逻辑记录对相关行的更改进行分组。您可以使用复制存储过程以编程方式指定项目之间的逻辑记录关系。

在没有关联的联接筛选器的情况下定义逻辑记录关系

  1. 如果发布包含已筛选的任何项目,则执行 sp_helpmergepublication,并注意结果集中的 use_partition_groups 值。

    • 如果值为 1,则已使用预计算分区。

    • 如果值为 0,请在发布服务器上对发布数据库执行 sp_changemergepublication。将 @property 的值指定为 use_partition_groups 并将 @value 的值指定为 true

      注意注意

      如果发布不支持预计算分区,则无法使用逻辑记录。有关详细信息,请参阅主题使用预计算分区优化参数化筛选器的性能中的“使用预计算分区的要求”。

    • 如果值为 NULL,则需要运行快照代理以生成发布的初始快照。

  2. 如果将包含逻辑记录的项目不存在,请在发布服务器上对发布数据库执行 sp_addmergearticle。为逻辑记录指定以下冲突检测和解决选项中的一项:

    • 若要检测并解决发生在逻辑记录的相关行之间的冲突,请将 @logical_record_level_conflict_detection@logical_record_level_conflict_resolution 的值指定为 true

    • 若要使用标准行级或列级冲突检测和解决方法,请将 @logical_record_level_conflict_detection@logical_record_level_conflict_resolution 的值指定为 false,此为默认值。

  3. 为每个将包含逻辑记录的项目重复步骤 2。您必须为逻辑记录中的每个项目使用相同的冲突检测和解决选项。有关详细信息,请参阅检测并解决逻辑记录中的冲突

  4. 在发布服务器上,对发布数据库执行 sp_addmergefilter。指定 @publication,将 @article 指定为该关系中一个项目的名称,将 @join_articlename 指定为第二个项目的名称,将 @filtername 指定为该关系的名称,将 @join_filterclause 指定为定义两个项目之间关系的子句,将**@join_unique_key** 指定为联接的类型,并将 @filter_type 指定为以下值之一:

    • 2 - 定义逻辑关系。

    • 3 - 定义与联接筛选器的逻辑关系。

    注意注意

    如果未使用联接筛选器,则两个项目之间的关系方向并不重要。

  5. 为发布中剩余的每个逻辑记录关系重复步骤 2。

为逻辑记录更改冲突检测和解决方法

  1. 检测和解决发生在逻辑记录中相关行之间的冲突:

    • 在发布服务器上,对发布数据库执行 sp_changemergearticle。将 @property 的值指定为 logical_record_level_conflict_detection,并将 @value 的值指定为 true。将 @force_invalidate_snapshot@force_reinit_subscription 的值指定为 1

    • 在发布服务器上,对发布数据库执行 sp_changemergearticle。将 @property 的值指定为 logical_record_level_conflict_resolution,并将 @value 的值指定为 true。将 @force_invalidate_snapshot@force_reinit_subscription 的值指定为 1

  2. 使用标准行级或列级冲突检测和解决方法:

    • 在发布服务器上,对发布数据库执行 sp_changemergearticle。将 @property 的值指定为 logical_record_level_conflict_detection,并将 @value 的值指定为 false。将 @force_invalidate_snapshot@force_reinit_subscription 的值指定为 1

    • 在发布服务器上,对发布数据库执行 sp_changemergearticle。将 @property 的值指定为 logical_record_level_conflict_resolution,并将 @value 的值指定为 false。将 @force_invalidate_snapshot@force_reinit_subscription 的值指定为 1

删除逻辑记录关系

  1. 在发布服务器上,对发布数据库执行以下查询,以返回有关为指定的发布定义的所有逻辑记录关系的信息:

    SELECT f.* FROM sysmergesubsetfilters AS f 
    INNER JOIN sysmergepublications AS p
    ON f.pubid = p.pubid WHERE p.[name] = @publication;
    

    注意在结果集 filtername 列中的被删除逻辑记录关系的名称。

    注意注意

    该查询返回的信息与 sp_helpmergefilter 相同;然而,该系统存储过程仅返回有关逻辑记录关系(也是联接筛选器)的信息。

  2. 在发布服务器上,对发布数据库执行 sp_dropmergefilter。指定 @publication,为 @article 指定该关系中其中一个项目的名称,并为 @filtername 指定步骤 1 中的关系的名称。

示例

本示例对现有发布启用预计算分区,并创建包含 SalesOrderHeader 和 SalesOrderDetail 表的两个新项目的逻辑记录。

-- Remove ON DELETE CASCADE from FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID;
-- logical records cannot be used with ON DELETE CASCADE. 
IF EXISTS (SELECT * FROM sys.objects 
WHERE name = 'FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID')
BEGIN
    ALTER TABLE [Sales].[SalesOrderDetail] 
    DROP CONSTRAINT [FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID] 
END

ALTER TABLE [Sales].[SalesOrderDetail]  
WITH CHECK ADD CONSTRAINT [FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID] 
FOREIGN KEY([SalesOrderID])
REFERENCES [Sales].[SalesOrderHeader] ([SalesOrderID])
GO

DECLARE @publication    AS sysname;
DECLARE @table1 AS sysname;
DECLARE @table2 AS sysname;
DECLARE @table3 AS sysname;
DECLARE @salesschema AS sysname;
DECLARE @hrschema AS sysname;
DECLARE @filterclause AS nvarchar(1000);
DECLARE @partitionoption AS bit;
SET @publication = N'AdvWorksSalesOrdersMerge'; 
SET @table1 = N'SalesOrderDetail'; 
SET @table2 = N'SalesOrderHeader'; 
SET @salesschema = N'Sales';
SET @hrschema = N'HumanResources';
SET @filterclause = N'Employee.LoginID = HOST_NAME()';

-- Ensure that the publication uses precomputed partitions.
SET @partitionoption = (SELECT [use_partition_groups] FROM sysmergepublications 
    WHERE [name] = @publication);
IF @partitionoption <> 1
BEGIN
    EXEC sp_changemergepublication 
        @publication = @publication, 
        @property = N'use_partition_groups', 
        @value = 'true',
        @force_invalidate_snapshot = 1;
END  

-- Add a filtered article for the Employee table.
EXEC sp_addmergearticle 
  @publication = @publication, 
  @article = @table1, 
  @source_object = @table1, 
  @type = N'table', 
  @source_owner = @hrschema,
  @schema_option = 0x0004CF1,
  @description = N'article for the Employee table',
  @subset_filterclause = @filterclause;

-- Add an article for the SalesOrderHeader table.
EXEC sp_addmergearticle 
  @publication = @publication, 
  @article = @table2, 
  @source_object = @table2, 
  @type = N'table', 
  @source_owner = @salesschema,
  @schema_option = 0x0034EF1,
  @description = N'article for the SalesOrderHeader table';

-- Add an article for the SalesOrderDetail table.
EXEC sp_addmergearticle 
  @publication = @publication, 
  @article = @table3, 
  @source_object = @table3, 
  @source_owner = @salesschema,
  @description = 'article for the SalesOrderDetail table', 
  @identityrangemanagementoption = N'auto', 
  @pub_identity_range = 100000, 
  @identity_range = 100, 
  @threshold = 80;

-- Add a merge join filter between Employee and SalesOrderHeader.
EXEC sp_addmergefilter 
  @publication = @publication, 
  @article = @table2, 
  @filtername = N'SalesOrderHeader_Employee', 
  @join_articlename = @table1, 
  @join_filterclause = N'Employee.EmployeeID = SalesOrderHeader.SalesPersonID', 
  @join_unique_key = 1, 
  @filter_type = 1, 
  @force_invalidate_snapshot = 1, 
  @force_reinit_subscription = 1;

-- Create a logical record relationship that is also a merge join 
-- filter between SalesOrderHeader and SalesOrderDetail.
EXEC sp_addmergefilter 
  @publication = @publication, 
  @article = @table3, 
  @filtername = N'LogicalRecord_SalesOrderHeader_SalesOrderDetail', 
  @join_articlename = @table2, 
  @join_filterclause = N'[SalesOrderHeader].[SalesOrderID] = [SalesOrderDetail].[SalesOrderID]', 
  @join_unique_key = 1, 
  @filter_type = 3, 
  @force_invalidate_snapshot = 1, 
  @force_reinit_subscription = 1;
GO