병합 테이블 아티클 간의 논리적 레코드 관계 정의

적용 대상:SQL Server

이 항목에서는 SQL Server Management Studio, Transact-SQL 또는 RMO(복제 관리 개체)를 사용하여 SQL Server의 병합 테이블 아티클 간에 논리적 레코드 관계를 정의하는 방법에 대해 설명합니다.

merge 복제본(replica)tion을 사용하면 서로 다른 테이블의 관련 행 간에 관계를 정의할 수 있습니다. 그러면 동기화 중에 이러한 행을 하나의 트랜잭션 단위로 처리할 수 있습니다. 조인 필터 관계가 있는지 여부에 관계없이 두 아티클 간에 논리적 레코드를 정의할 수 있습니다. 자세한 내용은 논리적 레코드를 사용하여 관련된 행의 변경 내용 그룹화를 참조하세요.

참고 항목

이 기능은 이후 버전의 SQL Server에서 제거됩니다. 새 개발 작업에서는 이 기능을 사용하지 않도록 하고, 현재 이 기능을 사용하는 애플리케이션은 수정하세요.

항목 내용

시작하기 전에

제한 사항

  • 게시에 대한 구독이 초기화된 후 논리 레코드를 추가, 수정 또는 삭제하는 경우 새 스냅샷 생성하고 변경한 후 모든 구독을 다시 초기화해야 합니다. 속성 변경 요구 사항에 대한 자세한 내용은 게시 및 아티클 속성 변경을 참조 하세요.

SQL Server Management Studio 사용

새 게시 마법사 및 게시 속성 -<>게시 대화 상자에서 사용할 수 있는 조인 추가 대화 상자에서 논리 레코드를 정의합니다. 마법사 사용 및 대화 상자 액세스에 대한 자세한 내용은 게시 만들기게시 속성 보기 및 수정을 참조하세요.

논리 레코드는 병합 게시의 조인 필터에 적용된 경우에만 조 인 추가 대화 상자에서 정의할 수 있으며 게시는 사전 계산 파티션을 사용하기 위한 요구 사항을 따릅니다. 조인 필터에 적용되지 않는 논리 레코드를 정의하고 논리적 레코드 수준에서 충돌 검색 및 해결을 설정하려면 저장 프로시저를 사용해야 합니다.

논리적 레코드 관계를 정의하려면

  1. 새 게시 마법사의 테이블 행 필터 페이지 또는 게시 속성 - <게시> 대화 상자의 필터 페이지에서 필터링된 테이블 창에서 행 필터를 선택합니다.

    논리적 레코드 관계는 조인 필터와 연결된 행 필터를 확장합니다. 따라서 조인 필터로 확장하기 전에 행 필터를 정의한 다음 논리적 레코드 관계를 적용해야 합니다. 하나의 조인 필터가 정의되면 다른 조인 필터를 사용하여 이 조인 필터를 확장할 수 있습니다. 조인 필터 정의 방법은 병합 아티클 사이에서 조인 필터 정의 및 수정을 참조하세요.

  2. 추가를 클릭한 다음 선택한 필터 확장을 위해 조인 추가를 클릭합니다.

  3. 조인 추가 대화 상자에서 조인 필터를 정의한 다음 검사 상자 논리 레코드를 선택합니다.

  4. 게시 속성 - <게시> 대화 상자에 있는 경우 [확인]을 클릭하여 대화 상자를 저장하고 닫습니다.

논리적 레코드 관계를 삭제하려면

  • 논리적 레코드 관계만 삭제하거나 논리 레코드 관계와 연결된 조인 필터를 삭제합니다.

    논리적 레코드 관계만 삭제하려면 다음을 수행합니다.

    1. 새 게시 마법사의 행 필터 페이지 또는 게시 속성 - <게시> 대화 상자의 필터 페이지에서 필터링된 테이블 창에서 논리적 레코드 관계와 연결된 조인 필터를 선택한 다음 편집을 클릭합니다.

    2. 조인 편집 대화 상자에서 검사 상자의 논리 레코드를 선택 취소합니다.

    3. 확인을 선택합니다.

    논리 레코드 관계를 삭제하고 연결된 조인 필터를 삭제하려면 다음을 수행합니다.

    • 새 게시 마법사 또는 게시 속성 - <게시> 대화 상자의 행 필터 페이지에서 필터링된 테이블 창에서 필터를 선택한 다음 삭제를 클릭합니다. 삭제한 조인 필터 자체가 다른 조인에 의해 확장된 경우 해당 조인도 삭제됩니다.

Transact-SQL 사용

복제 저장 프로시저를 사용하여 아티클 간 논리적 레코드 관계를 프로그래밍 방식으로 지정할 수 있습니다.

연결된 조인 필터 없이 논리적 레코드 관계를 정의하려면

  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을 실행합니다. @propertylogical_record_level_conflict_detection 값을 지정하고 @valuetrue값을 지정합니다. @force_invalidate_스냅샷 및 @force_reinit_subscription 값 1지정합니다.

    • 게시 데이터베이스의 게시자에서 sp_changemergearticle을 실행합니다. @propertylogical_record_level_conflict_resolution 값을 지정하고 @valuetrue값을 지정합니다. @force_invalidate_스냅샷 및 @force_reinit_subscription 값 1지정합니다.

  2. 표준 행 수준 또는 열 수준 충돌 검색 및 해결 방법을 사용하려면 다음을 수행합니다.

    • 게시 데이터베이스의 게시자에서 sp_changemergearticle을 실행합니다. @property logical_record_level_conflict_detection과 @value false값을 지정합니다. @force_invalidate_스냅샷 및 @force_reinit_subscription 값 1지정합니다.

    • 게시 데이터베이스의 게시자에서 sp_changemergearticle을 실행합니다. @propertylogical_record_level_conflict_resolution 값을 지정하고 @valuefalse값을 지정합니다. @force_invalidate_스냅샷 및 @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;
    

    결과 집합의 필터 이름 열에서 제거되는 논리적 레코드 관계의 이름을 확인합니다.

    참고 항목

    이 쿼리는 sp_helpmergefilter와 동일한 정보를 반환하지만, 이 시스템 저장 프로시저는 조인 필터이기도 한 논리적 레코드 관계에 대한 정보만 반환합니다.

  2. 게시 데이터베이스의 게시자에서 sp_dropmergefilter를 실행합니다. @publication, @article 관계에 있는 아티클 중 하나의 이름 및 @filtername 1단계의 관계 이름을 지정합니다.

예제(Transact-SQL)

이 예제에서는 기존 게시에서 미리 계산된 파티션을 사용하도록 설정하고 두 개의 새 아티클과 SalesOrderDetail 테이블로 구성된 논리 레코드를 SalesOrderHeader 만듭니다.

-- 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

RMO(복제 관리 개체) 사용

참고 항목

병합 복제본(replica)에서는 논리적 레코드 수준에서 충돌을 추적하고 해결하도록 지정할 수 있지만 RMO를 사용하여 이러한 옵션을 설정할 수는 없습니다.

연결된 조인 필터 없이 논리적 레코드 관계를 정의하려면

  1. ServerConnection 클래스를 사용하여 게시자 연결을 만듭니다.

  2. MergePublication 클래스의 인스턴스를 만들고 게시에 대한 NameDatabaseName 속성을 설정한 다음, 1단계에서 만든 연결에 ConnectionContext 속성을 설정합니다.

  3. LoadProperties 메서드를 호출하여 개체 속성을 가져옵니다. 이 메서드가 false를 반환하는 경우 2단계의 게시 속성이 잘못 정의되었거나 게시가 존재하지 않습니다.

  4. 속성이 PartitionGroupsOption 설정 False되면 .로 설정합니다 True.

  5. 논리 레코드를 구성하는 아티클이 없으면 클래스의 인스턴스를 MergeArticle 만들고 다음 속성을 설정합니다.

    • 에 대한 아티클의 이름입니다 Name.

    • 에 대한 게시의 이름입니다 PublicationName.

    • (선택 사항) 아티클이 가로로 필터링되는 경우 속성에 대한 행 필터 절을 지정합니다 FilterClause . 정적 또는 매개 변수가 있는 행 필터를 지정하려면 이 속성을 사용합니다. 자세한 내용은 매개 변수가 있는 행 필터를 참조하십시오.

    자세한 내용은 아티클 정의를 참조 하세요.

  6. Create 메서드를 호출합니다.

  7. 논리 레코드를 구성하는 각 아티클에 대해 5단계와 6단계를 반복합니다.

  8. 아티클 간의 논리적 레코드 관계를 정의하는 클래스의 MergeJoinFilter 인스턴스를 만듭니다. 그런 다음, 다음 속성을 설정합니다.

  9. AddMergeJoinFilter 관계의 자식 아티클을 나타내는 개체의 메서드를 호출합니다. MergeJoinFilter 8단계에서 개체를 전달하여 관계를 정의합니다.

  10. 게시의 논리적 레코드 관계를 다시 기본 각각에 대해 8단계와 9단계를 반복합니다.

예제(RMO)

이 예제에서는 두 개의 새 아티클 및 SalesOrderDetail 테이블로 구성된 논리 레코드를 SalesOrderHeader 만듭니다.

           // Define the Publisher and publication names.
           string publisherName = publisherInstance;
           string publicationName = "AdvWorksSalesOrdersMerge";
           string publicationDbName = "AdventureWorks2022";

           // Specify article names.
           string articleName1 = "SalesOrderHeader";
           string articleName2 = "SalesOrderDetail";
           
           // Specify logical record information.
           string lrName = "SalesOrderHeader_SalesOrderDetail";
           string lrClause = "[SalesOrderHeader].[SalesOrderID] = "
               + "[SalesOrderDetail].[SalesOrderID]";

           string schema = "Sales";

           MergeArticle article1 = new MergeArticle();
           MergeArticle article2 = new MergeArticle();
           MergeJoinFilter lr = new MergeJoinFilter();
           MergePublication publication = new MergePublication();

           // Create a connection to the Publisher.
           ServerConnection conn = new ServerConnection(publisherName);

           try
           {
               // Connect to the Publisher.
               conn.Connect();

               // Verify that the publication uses precomputed partitions.
               publication.Name = publicationName;
               publication.DatabaseName = publicationDbName;
               publication.ConnectionContext = conn;

               // If we can't get the properties for this merge publication, then throw an application exception.
               if (publication.LoadProperties())
               {
                   // If precomputed partitions is disabled, enable it.
                   if (publication.PartitionGroupsOption == PartitionGroupsOption.False)
                   {
                       publication.PartitionGroupsOption = PartitionGroupsOption.True;
                   }
               }
               else
               {
                   throw new ApplicationException(String.Format(
                       "Settings could not be retrieved for the publication. " +
                       "Ensure that the publication {0} exists on {1}.",
                       publicationName, publisherName));
               }

               // Set the required properties for the PurchaseOrderHeader article.
               article1.ConnectionContext = conn;
               article1.Name = articleName1;
               article1.DatabaseName = publicationDbName;
               article1.SourceObjectName = articleName1;
               article1.SourceObjectOwner = schema;
               article1.PublicationName = publicationName;
               article1.Type = ArticleOptions.TableBased;

               // Set the required properties for the SalesOrderDetail article.
               article2.ConnectionContext = conn;
               article2.Name = articleName2;
               article2.DatabaseName = publicationDbName;
               article2.SourceObjectName = articleName2;
               article2.SourceObjectOwner = schema;
               article2.PublicationName = publicationName;
               article2.Type = ArticleOptions.TableBased;

               if (!article1.IsExistingObject) article1.Create();
               if (!article2.IsExistingObject) article2.Create();

               // Define a logical record relationship between 
               // PurchaseOrderHeader and PurchaseOrderDetail. 

               // Parent article.
               lr.JoinArticleName = articleName1;
               
               // Child article.
               lr.ArticleName = articleName2;
               lr.FilterName = lrName;
               lr.JoinUniqueKey = true;
               lr.FilterTypes = FilterTypes.LogicalRecordLink;
               lr.JoinFilterClause = lrClause;

               // Add the logical record definition to the parent article.
               article1.AddMergeJoinFilter(lr);
           }
           catch (Exception ex)
           {
               // Do error handling here and rollback the transaction.
               throw new ApplicationException(
                   "The filtered articles could not be created", ex);
           }
           finally
           {
               conn.Disconnect();
           }
' Define the Publisher and publication names.
Dim publisherName As String = publisherInstance
Dim publicationName As String = "AdvWorksSalesOrdersMerge"
Dim publicationDbName As String = "AdventureWorks2022"

' Specify article names.
Dim articleName1 As String = "SalesOrderHeader"
Dim articleName2 As String = "SalesOrderDetail"

' Specify logical record information.
Dim lrName As String = "SalesOrderHeader_SalesOrderDetail"
Dim lrClause As String = "[SalesOrderHeader].[SalesOrderID] = " _
        & "[SalesOrderDetail].[SalesOrderID]"

Dim schema As String = "Sales"

Dim article1 As MergeArticle = New MergeArticle()
Dim article2 As MergeArticle = New MergeArticle()
Dim lr As MergeJoinFilter = New MergeJoinFilter()
Dim publication As MergePublication = New MergePublication()

' Create a connection to the Publisher.
Dim conn As ServerConnection = New ServerConnection(publisherName)

Try
    ' Connect to the Publisher.
    conn.Connect()

    ' Verify that the publication uses precomputed partitions.
    publication.Name = publicationName
    publication.DatabaseName = publicationDbName
    publication.ConnectionContext = conn

    ' If we can't get the properties for this merge publication, then throw an application exception.
    If publication.LoadProperties() Then
        ' If precomputed partitions is disabled, enable it.
        If publication.PartitionGroupsOption = PartitionGroupsOption.False Then
            publication.PartitionGroupsOption = PartitionGroupsOption.True
        End If
    Else
        Throw New ApplicationException(String.Format( _
            "Settings could not be retrieved for the publication. " _
            & "Ensure that the publication {0} exists on {1}.", _
            publicationName, publisherName))
    End If

    ' Set the required properties for the SalesOrderHeader article.
    article1.ConnectionContext = conn
    article1.Name = articleName1
    article1.DatabaseName = publicationDbName
    article1.SourceObjectName = articleName1
    article1.SourceObjectOwner = schema
    article1.PublicationName = publicationName
    article1.Type = ArticleOptions.TableBased

    ' Set the required properties for the SalesOrderDetail article.
    article2.ConnectionContext = conn
    article2.Name = articleName2
    article2.DatabaseName = publicationDbName
    article2.SourceObjectName = articleName2
    article2.SourceObjectOwner = schema
    article2.PublicationName = publicationName
    article2.Type = ArticleOptions.TableBased

    If Not article1.IsExistingObject Then
        article1.Create()
    End If
    If Not article2.IsExistingObject Then
        article2.Create()
    End If

    ' Define a logical record relationship between 
    ' SalesOrderHeader and SalesOrderDetail. 

    ' Parent article.
    lr.JoinArticleName = articleName1
    ' Child article.
    lr.ArticleName = articleName2
    lr.FilterName = lrName
    lr.JoinUniqueKey = True
    lr.FilterTypes = FilterTypes.LogicalRecordLink
    lr.JoinFilterClause = lrClause

    ' Add the logical record definition to the parent article.
    article1.AddMergeJoinFilter(lr)
Catch ex As Exception
    ' Do error handling here and rollback the transaction.
    Throw New ApplicationException( _
            "The filtered articles could not be created", ex)
Finally
    conn.Disconnect()
End Try

참고 항목

병합 아티클 간의 조인 필터 정의 및 수정
병합 아티클에 대한 매개 변수가 있는 행 필터 정의 및 수정
정적 행 필터 정의 및 수정
논리적 레코드를 사용하여 관련된 행의 변경 내용 그룹화
사전 계산 파티션으로 매개 변수가 있는 필터 성능 최적화
논리적 레코드를 사용하여 관련된 행의 변경 내용 그룹화