トランザクション記事 - 変更の伝播方法を指定する

適用対象:SQL ServerAzure SQL Managed Instance

トランザクション レプリケーションを使用すると、パブリッシャーからサブスクライバーに変更を反映する方法を指定できます。 パブリッシュされたテーブルごとに、各操作 (INSERT、 UPDATE、または DELETE) をサブスクライバーに伝達する 4 つの方法のいずれかを指定できます。

  • トランザクション レプリケーションのスクリプトを作成し、その後、ストアド プロシージャを呼び出して変更をサブスクライバーに反映するように指定します (既定値)。

  • INSERT、UPDATE、または DELETE ステートメント (SQL Server 以外のサブスクライバーの既定値) を使用して変更を反映することを指定します。

  • カスタム ストアド プロシージャを使用するように指定します。

  • この操作がサブスクライバーで実行されないように指定します。 その種類のトランザクションはレプリケートされません。

既定では、トランザクション レプリケーションが、各サブスクライバーにインストールされているストアド プロシージャのセットを使用して、変更をサブスクライバーに伝達します。 パブリッシャーでテーブルに挿入、更新、または削除が発生した場合、各操作はサブスクライバーでのストアド プロシージャへの呼び出しに翻訳されます。 ストアド プロシージャは、テーブル内の列にマップされるパラメーターを受け入れ、それらの列がサブスクライバーで変更されることを許可します。

データの変更をトランザクション アーティクルに反映する方法を設定するには、「 データの変更をトランザクション アーティクルに反映する方法の設定」を参照してください。

既定のストアド プロシージャとカスタム ストアド プロシージャ

レプリケーションは各テーブル記事に対して3つのデフォルトのストアドプロシージャを作成します:

  • sp_MSins_<tablename>。挿入処理を行います。

  • sp_MSupd_<tablename>。更新処理を行います。

  • sp_MSdel_<tablename>。これは削除を処理します。

手順で使われる <tablename> は、論文をどのように出版物に追加するか、また購読データベースに同じ名前のテーブルが所有者が異なるかどうかによって異なります。

これらの手順は、記事を出版物に追加する際に指定したカスタム手順に置き換えることができます。 サブスクライバーで行が更新される際に監査テーブルにデータを挿入するなど、アプリケーションがカスタムロジックを必要とする場合はカスタム手続きを用いましょう。 カスタムストアドプロシージャの仕様についての詳細は、前述のハウツー記事をご覧ください。

デフォルトのレプリケーション手続きかカスタム手続きを指定する場合、それぞれの手続きごとに呼び出し構文も指定します。 レプリケーションはデフォルト手続きを使うとデフォルトの呼び出し構文を選択します。 呼び出し構文によって、プロシージャに提供されたパラメーターの構造、および各データの変更と共にサブスクライバーに送信される情報の量が決定されます。 詳細については、本記事の「Call Syntax for Stored Procedures」のセクションをご覧ください。

カスタムストアドプロシージャ使用時の考慮事項

カスタム ストアド プロシージャを使用する場合は、次の点に注意してください。

  • ストアドプロシージャ内でロジックをサポートしなければなりません;Microsoftはカスタムロジックのサポートを提供していません。

  • レプリケーションで使われるトランザクションとの競合を避けるために、カスタムプロシージャで明示的なトランザクションは使わないでください。

  • Subscriberのスキーマは通常Publisherのスキーマと同じですが、カラムフィルタリングを使う場合はPublisherスキーマのサブセットにもなり得ます。 データ移動に合わせてスキーマを変換し、SubscriberのスキーマがPublisherのスキーマのサブセットにならないようにする必要がある場合は、SQL Server 2019 Integration Services(SSIS)を使いましょう。 詳細については、「 SQL Server Integration Services」を参照してください。

  • 公開されたテーブルにスキーマを変更した場合は、カスタムプロシージャを再生成してください。 詳細については、「カスタム トランザクション プロシージャの再生成によるスキーマ変更の反映」を参照してください。

  • ディストリビューション エージェントの-SubscriptionStreamsパラメータに1より大きい値を使用した場合、プライマリキーカラムへの更新が成功することを確認してください。 次に例を示します。

    update ... set pk = 2 where pk = 1 -- update 1  
    update ... set pk = 3 where pk = 2 -- update 2  
    

    ディストリビューション エージェントが複数の接続を使用している場合、これら2つの更新は異なる接続で複製されることがあります。 アップデート1を先に適用すれば問題ありません。 もしアップデート2が先に適用された場合、アップデート1がまだ発生していないため、返 0 rows affected します。 デフォルトの手続きでは、更新時に行が影響を受けていない場合にエラーを出すことでこの状況を処理します:

    if @@rowcount = 0  
        if @@microsoftversion>0x07320000  
            exec sys.sp_MSreplraiserror 20598  
    

    エラーを発生させると、ディストリビューション エージェントは単一の接続で更新を再試行し、成功します。 カスタム ストアド プロシージャには、これと同様のロジックを含める必要があります。

ストアド プロシージャの呼び出し構文

トランザクションレプリケーションが使用する手続きを呼び出すために、5つの異なる構文オプションを使用できます:

  • CALL構文。 この構文は挿入、更新、削除に使います。 既定では、レプリケーションは挿入と削除に対してこの構文を使用します。

  • SCALL 構文。 この構文は更新時のみ使用してください。 既定では、レプリケーションは更新に対してこの構文を使用します。

  • MCALL 構文。 この構文は更新時のみ使用してください。

  • XCALL 構文。 この構文は更新や削除に使ってください。

  • VCALL。 この構文は更新可能なサブスクリプションに使ってください。 内部のみで使用します。

各方法は加入者に送るデータ量に違いがあります。 例えば、SCALLは更新が実際に影響を受ける列の値のみを渡します。 XCALLは、更新が影響を及ぼすかどうかにかかわらず、すべての列と各列の古いデータ値を必要とします。 多くの場合、SCALLは更新に適していますが、アプリケーションが更新時にすべてのデータ値を必要とする場合、XCALLはこのニーズをサポートしています。

CALL 構文

INSERT ストアドプロシージャ
INSERT ステートメントを処理するストアドプロシージャは、すべての列の挿入された値を受け取ります。

c1, c2, c3,... cn  

UPDATE ストアドプロシージャ
UPDATE文を処理するストアドプロシージャは、記事で定義されたすべての列の更新された値を受け取り、その後にプライマリキー列の元の値を受け取ります。 このプロセスは、どの列が変わったかを特定しようとはしません。

c1, c2, c3,... cn, pkc1, pkc2, pkc3,... pkcn  

DELETE ストアドプロシージャ
文を処理するストアドプロシージャ DELETE プライマリキーカラムの値を受け取ります:

pkc1, pkc2, pkc3,... pkcn  

SCALL構文

UPDATE ストアドプロシージャ
UPDATE文を処理するストアドプロシージャは、変更された列のみの更新された値を受け取り、その後に主キー列の元の値、そして変更された列を示すビットマスク(binary(n))パラメータを受け取ります。 次の例では、列2(c2)は変わりませんでした:

c1, , c3,... cn, pkc1, pkc2, pkc3,... pkcn, bitmask  

MCALL 構文

UPDATE ストアドプロシージャ
文 UPDATE を扱うストアドプロシージャは、記事で定義されたすべての列の更新された値を受け取り、その後に主キー列の元の値を受け取り、さらに変更された列を示すビットマスク(binary(n))パラメータを受け取ります。

c1, c2, c3,... cn, pkc1, pkc2, pkc3,... pkcn, bitmask  

XCALL 構文

UPDATE ストアドプロシージャ
UPDATE文を処理するストアドプロシージャは、記事で定義されたすべての列に対して元の値(ビフォーイメージ)を受け取り、その後に記事で定義されたすべての列の更新された値(アフターイメージ)を受け取ります。

old-c1, old-c2, old-c3,... old-cn, c1, c2, c3,... cn,  

DELETE ストアドプロシージャ
DELETE文を処理するストアドプロシージャは、記事で定義されたすべての列に対して元の値(ビフォーイメージ)を受け取ります。

old-c1, old-c2, old-c3,... old-cn  

注

XCALLを使うと、 text 列と image 列の画像前の値は NULLされるはずです。

例

次のプロシージャは、Adventure Works サンプル データベース内の Vendor Table に対して作成された既定のプロシージャです。

--INSERT procedure using CALL syntax  
create procedure [sp_MSins_PurchasingVendor]   
  @c1 int,@c2 nvarchar(15),@c3 nvarchar(50),@c4 tinyint,@c5 bit,@c6 bit,@c7 nvarchar(1024),@c8 datetime  
as   
begin   
insert into [Purchasing].[Vendor]([VendorID]  
,[AccountNumber]  
,[Name]  
,[CreditRating]  
,[PreferredVendorStatus]  
,[ActiveFlag]  
,[PurchasingWebServiceURL]  
,[ModifiedDate])  
values (   
 @c1  
,@c2  
,@c3  
,@c4  
,@c5  
,@c6  
,@c7  
,@c8  
 )   
end  
go  
  
--UPDATE procedure using SCALL syntax  
create procedure [sp_MSupd_PurchasingVendor]   
 @c1 int = null,@c2 nvarchar(15) = null,@c3 nvarchar(50) = null,@c4 tinyint = null,@c5 bit = null,@c6 bit = null,@c7 nvarchar(1024) = null,@c8 datetime = null,@pkc1 int  
,@bitmap binary(2)  
as  
begin  
update [Purchasing].[Vendor] set   
 [AccountNumber] = case substring(@bitmap,1,1) & 2 when 2 then @c2 else [AccountNumber] end  
,[Name] = case substring(@bitmap,1,1) & 4 when 4 then @c3 else [Name] end  
,[CreditRating] = case substring(@bitmap,1,1) & 8 when 8 then @c4 else [CreditRating] end  
,[PreferredVendorStatus] = case substring(@bitmap,1,1) & 16 when 16 then @c5 else [PreferredVendorStatus] end  
,[ActiveFlag] = case substring(@bitmap,1,1) & 32 when 32 then @c6 else [ActiveFlag] end  
,[PurchasingWebServiceURL] = case substring(@bitmap,1,1) & 64 when 64 then @c7 else [PurchasingWebServiceURL] end  
,[ModifiedDate] = case substring(@bitmap,1,1) & 128 when 128 then @c8 else [ModifiedDate] end  
where [VendorID] = @pkc1  
if @@rowcount = 0  
    if @@microsoftversion>0x07320000  
        exec sp_MSreplraiserror 20598  
end  
go  
  
--DELETE procedure using CALL syntax  
create procedure [sp_MSdel_PurchasingVendor]   
  @pkc1 int  
as   
begin   
delete [Purchasing].[Vendor]  
where [VendorID] = @pkc1  
if @@rowcount = 0  
    if @@microsoftversion>0x07320000  
        exec sp_MSreplraiserror 20598  
end   
go