トランザクションレプリケーションのID範囲の処理


9

トランザクションレプリケーションを設定すると、SQL ServerがID範囲の管理を手動に設定することに気付きました。つまり、サブスクリプションデータベースで、PKがID列であるテーブルに新しいレコードを挿入しようとすると、エラーが発生し、「1」、「2」のPKを挿入しようとしたと表示されます。 "、" 3 "などです。これは、サブスクライバーのすべてのID列の現在のID値が、パブリッシャーの状態に留まるのではなく、シード値(通常は1)にリセットされるためです。

SQL Serverがこれを行う理由を理解しました。サブスクライバーテーブルを読み取り専用のままにすることになっています。ただし、私のシナリオは少し正統ではありません-レプリケーションを通じて時々サブスクライバーを更新し、そのDBの即時バックアップを作成してから、サブスクライバーにいくつかの更新を実行して、パブリッシャーにプッシュバックされないようにします。サブスクライバを再度更新するときに、以前のバックアップからデータベースを復元し、最新の更新を取得します。これらの更新の間にサブスクライバーを更新したいので(可能であれば「一時的なデルタ」)、レプリケート時にID列が機能し、1にリセットされないようにする必要があります。

パブリケーションの設定時に自動ID範囲管理をオンにしようとしましたが、パブリケーションにテーブルを追加しようとすると、次のエラーが表示されます。

メッセージ21231、レベル16、状態1、プロシージャsp_MSrepl_addarticle、行2243
自動ID範囲のサポートは、サブスクライバーの更新を許可するパブリケーションでのみ役立ちます。

この問題を回避する方法はありますか?このレプリケーションをサブスクライバー側で読み取り専用であるかのようにSQL Serverに提示したいのですが、パブリッシャーにプッシュバックされる更新を行う予定はありませんが、一時的な更新を行います次の複製の前に消去されます。

スナップショットレプリケーションは、私の使用パターンではトランザクションレプリケーションよりも適切な方法であると考えましたが、問題は、スナップショットレプリケーションでは更新ごとにすべてのデータベースを送信する必要があることです。最新のレプリケーションの後でDBの即時バックアップを取ることを計画しているため、毎回転送全体を実行する必要はありません。前回からの変化だけです。


SQL Serverのどのバージョンを使用していますか?テーブルを再定義できますか?

2008 R2。テーブルを再定義するとこの問題がどのように解決されるかわかりません...
Jez

SEQUENCEを使用した解決策を考えていましたが、それはSQL 2012の場合のみです

2
Is there any way I can get round this problem?SQL Server 2005 以降ではsys.sp_identitycolumnforreplicationを使用してID列をNOT FOR REPLICATIONとして設定する必要があります。レプリケーション用ではないようにID列を変更しても、記事を再スナップショットする必要はありません。GUIを使用しないでください。
キンシャー

レプリケーション対象外としてすでにマークされています。それは基本的に問題だ- SQL Serverは、加入者にその識別情報をコピーしません、それは1でやり直す
ジェズ

回答:


3

パブリッシャーが1から始まるint IDを使用していると仮定するとDBCC CHECKIDENT('dbo.mytable', RESEED, -2147483648) 、サブスクライバーで発行でき ます。次に、-2147483648から0の範囲を使用して、「一時的なデルタ」を保持できます。


これは私が思いついたソリューションですが、それでも私のコードはパブリッシャーとサブスクライバーに接続し、IDを手動で同期することを意味します。私はそれを行うためのより自動的な方法があることを望んでいました。
Jez

IDを手動で同期する必要があるのはなぜですか?一時的なデルタを格納している各テーブルのcheckidentを実行するストアドプロシージャをサブスクライバーに記述し、スナップショットの適用が完了した後で実行するだけです。ディストリビューションエージェントは、 "実際の" ID範囲で発生する変更を挿入します。サブスクライバーに直接加えられた変更は、負の範囲になります。
リアムコンフリー2013

1

私がやったことは、プルベースのトランザクションレプリケーションに固執し、同期の直後にプログラムがパブリケーションデータベースの値と同じになるようにサブスクライバーID値を更新することでした(ディストリビューションエージェントが独自に実行したいと思っていること) )。疑似コードでは、次のようになります。

synchronize databases with TransSynchronizationAgent

equivalentTablesNotFound is a list of strings
for each table in publisher tables:
    try:
        check table identity value (this is via functionality provided by .NET's Microsoft.SqlServer.Management.Smo.Server class)
        parse identity value as integer to newIdentity
        if the table's identity value was NULL, skip to next loop iteration
        (HACK) increment newIdentity value by 1
        if there is no subscriber table with the same name as this one:
            record its name in equivalentTablesNotFound and skip to next loop iteration
        set subscriber table with same name's identity value to newIdentity using TSQL: DBCC CHECKIDENT ("tableName", newIdentity)
    catch:
        if exception shows that the error was because the table doesn't have an identity column, drop the exception

if equivalentTablesNotFound has more than zero entries, warn about tables on publisher without an equivalent name on subscriber

正常に動作するようです。HACKビットは、デフォルトでは、すべてのテーブルでID値が1ずつ増加するだけですが、異なる方法で構成できるため、技術的にここでは、パブリッシャーテーブルでID値がどのように増加し、それが増加するかを確認する必要があります同じ方法。


0

これを処理するための私の好ましい方法は、以下を実行することです。

a。最初にレプリケーションエージェントを停止します(サブスクライバーDBに新しいデータを取得しません)。

b。次に、既存のテーブルの名前を変更します

exec sp_rename '[CurrentTable]', '[BackupTableName]'

c。IDENTITYを設定してテーブルを再作成します

CREATE TABLE [CurrentTable]
(
   ID INT NOT NULL IDENTITY(1,1), 
   OtherField VARCHAR(10) NULL,
   ....
)

d。SET IDENTITY_INSERTを使用して([BackupTableName]から)テーブルをバックフィルします。

SET IDENTITY_INSERT [CurrentTable] ON
INSERT INTO [CurrentTable] (ID, OtherField, ...)
SELECT ID, OtherField, ....
FROM [BackupTableName]
SET IDENTITY_INSERT [CurrentTable] OFF

あなたが持ってたらIDENTITYのあなたのDB上の制約を、あなたはどちらかのカスタム複製を行うことができます(例:SET IDENTITY_INSERT [テーブル名] ONにあなたの挿入REPLのPROCを変更するか、SQLサーバーのことを伝え、テーブルのレプリケーションフラグ(のためではない設定することができます接続しているユーザーがレプリケーションエージェントの場合、IDENTITY値が提供されることを期待します)(カスタムレプリケーションアプローチを使用します。柔軟性が高まるためです)。

e。挿入レプリケーションストアドプロシージャ(通常はsp_MSins_CurrentTableという名前)を変更して、SET IDENTITY INSERT

ALTER procedure [dbo].[sp_MSins_CurrentTable]
    @c1 int, @c2 varchar(50), ...
as
begin
    /* allow replication to insert values for IDENTITY */
    SET IDENTITY_INSERT [CurrentTable] ON
    insert into [CurrentTable]
        ([ID], [OtherField], ...)
    values
        (@c1, @c2, ...)
    /* now turn off Identity insert */
    SET IDENTITY_INSERT [CurrentTable] OFF
end

f。これで、レプリケーションエージェントを再起動できます。


1
笑、を使用する場合と比較してDBCC CHECKIDENT、この方法は膨大な量の作業です。
Jez

@Jez DBCC CHECKIDENTを実行するには、テーブルを(IDENTITYで)再作成する必要があります...レプリケーションのスナップショットにより、IDENTITY制約なしでテーブルが作成されます(qに基づいて、DBCC CHECKIDENTが勝ったと思います)動作し
ません

ちなみにそれは機能し、レプリケーションはIDENTITY制約でテーブルを作成します...
Jez

@Jezどのタイプのレプリケーションをセットアップしましたか?(発生するMERGEとして設定した場合、TRANSACTIONALの場合は通常は発生しませんが、GUIを使用しない場合、レプリケーションは高度にカスタマイズ可能です)
Andrew Bickerton 2013

トランザクション。IDENTITYはそこにありますが、現在のID値はシード値(1)にリセットされます。
Jez
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.