Berurusan dengan rentang identitas untuk replikasi transaksional

9

Saya perhatikan bahwa ketika Anda mengatur replikasi transaksional, SQL Server akan mengatur manajemen rentang identitas ke manual. Apakah ini berarti bahwa dalam database berlangganan saya, ketika saya mencoba untuk memasukkan catatan baru ke dalam tabel yang PK-nya adalah kolom identitas, itu akan memberi saya kesalahan dan mengatakan bahwa ia mencoba memasukkan PK "1", "2 "," 3 ", dll. Ini karena nilai identitas saat ini untuk semua kolom identitas pada pelanggan akan diatur ulang ke nilai awal (biasanya 1) alih-alih tetap seperti pada penerbit.

Saya mengerti mengapa SQL Server melakukan ini - Anda seharusnya membiarkan tabel pelanggan sebagai read-only. Namun, skenario saya sedikit tidak lazim - saya memperbarui pelanggan saya dari waktu ke waktu melalui replikasi, membuat cadangan langsung dari DB itu, maka saya ingin melakukan beberapa pembaruan kepada pelanggan bahwa TIDAK AKAN didorong kembali ke penerbit, lalu ketika saya pergi untuk memperbarui pelanggan lagi, saya mengembalikan databasenya dari cadangan sebelumnya dan menarik pembaruan terbaru. Karena saya ingin melakukan pembaruan untuk pelanggan di antara pembaruan ini ('sementara delta' jika Anda mau), saya perlu kolom identitas untuk bekerja dan tidak mengatur ulang ke 1 ketika direplikasi.

Saya mencoba mengaktifkan manajemen rentang identitas otomatis saat menyiapkan publikasi saya, tetapi itu hanya memberi saya kesalahan berikut ketika saya mencoba menambahkan tabel ke publikasi:

Msg 21231, Level 16, Negara Bagian 1, Prosedur sp_MSrepl_addarticle, Baris 2243
Dukungan rentang identitas otomatis hanya berguna untuk publikasi yang memperbolehkan memperbarui pelanggan.

Apakah ada cara saya bisa mengatasi masalah ini? Saya memang ingin menyajikan replikasi ini ke SQL Server seolah-olah hanya-baca di akhir pelanggan karena saya tidak berencana membuat pembaruan yang akan didorong kembali ke penerbit , tetapi saya ingin membuat pembaruan sementara yang akan dihapus sebelum replikasi berikutnya.

Saya juga telah mempertimbangkan bahwa replikasi snapshot mungkin merupakan metode yang lebih tepat daripada replikasi transaksional untuk pola penggunaan saya, tetapi masalahnya adalah replikasi snapshot memerlukan pengiriman seluruh DB setiap pembaruan tunggal; karena saya berencana mengambil cadangan langsung DB setelah replikasi terbaru, saya tidak perlu melakukan seluruh transfer setiap waktu; hanya perubahan sejak terakhir kali.

Jez
sumber
Apa versi SQL Server yang Anda gunakan? Bisakah Anda mendefinisikan ulang tabel?
2008 r2. Saya tidak melihat bagaimana mendefinisikan ulang tabel akan memecahkan masalah ini ...
Jez
Saya sedang memikirkan solusi menggunakan URUTAN, tapi itu hanya untuk SQL 2012.
2
Is there any way I can get round this problem?Anda harus mengatur kolom identitas sebagai BUKAN UNTUK REPLIKASI menggunakan sys.sp_identitycolumnforreplication untuk sql server 2005 dan lebih tinggi. Anda bahkan tidak perlu mengulang artikel Anda ketika Anda mengubah kolom identitas bukan untuk replikasi. Jangan lakukan itu menggunakan GUI.
Kin Shah
Sudah ditandai tidak untuk replikasi. Itu pada dasarnya masalahnya - SQL Server tidak menyalin informasi identitas sehingga pada pelanggan, itu dimulai pada 1.
Jez

Jawaban:

3

Dengan asumsi Penerbit Anda menggunakan identitas int yang dimulai pada 1, Anda bisa mengeluarkan DBCC CHECKIDENT('dbo.mytable', RESEED, -2147483648) pada pelanggan. Anda kemudian dapat menggunakan rentang dari -2147483648 hingga 0 untuk menahan "delta sementara" Anda.

Liam Confrey
sumber
Ini adalah solusi yang saya buat, tetapi masih berarti kode saya terhubung ke penerbit dan pelanggan dan menyinkronkan identitas secara manual. Saya berharap ada cara yang lebih otomatis untuk melakukannya.
Jez
Mengapa Anda perlu menyinkronkan identitas secara manual? Cukup tulis prosedur tersimpan di pelanggan yang menjalankan checkident untuk setiap tabel tempat Anda menyimpan delta sementara, dan jalankan setelah snapshot selesai diterapkan. Agen distribusi akan memasukkan perubahan saat terjadi dalam rentang identitas "nyata", dan perubahan yang dibuat langsung ke pelanggan akan berada dalam kisaran negatif.
Liam Confrey
1

Apa yang akhirnya saya lakukan adalah tetap dengan replikasi transaksional berbasis tarik, dan memiliki program saya memperbarui nilai-nilai identitas pelanggan menjadi sama dengan yang ada di database publikasi segera setelah sinkronisasi (agak apa yang saya berharap agen distribusi lakukan dengan kemauan sendiri ). Dalam pseudo-code tampilannya sedikit seperti ini:

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

Tampaknya bekerja dengan baik. Bit HACK adalah karena, meskipun secara default dan dengan semua tabel saya, nilai identitas hanya bertambah satu, itu dapat dikonfigurasi secara berbeda, jadi secara teknis di sini Anda harus mencari tahu bagaimana nilai identitas meningkat pada tabel penerbit dan menambahkannya pada cara yang sama.

Jez
sumber
0

Metode pilihan saya untuk menangani ini adalah dengan melakukan hal berikut:

Sebuah. Pertama-tama hentikan agen replikasi Anda (jadi Anda tidak mendapatkan data baru ke dalam DB pelanggan Anda)

b. Ubah nama kedua tabel yang ada

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

c. Buat kembali meja Anda dengan set IDENTITY

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

d. Isi ulang meja Anda (dari [BackupTableName]) dengan SET IDENTITY_INSERT

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

Setelah Anda memiliki batasan IDENTITY pada DB Anda, maka Anda dapat melakukan replikasi khusus (yaitu: mengubah proc pengadaan sisipkan Anda ke SET IDENTITY_INSERT [TableName] ON atau Anda dapat mengatur tanda NOT FOR REPLICATION di atas meja (yang memberi tahu SQL server bahwa jika pengguna yang terhubung adalah agen replikasi, harap nilai IDENTITAS diberikan ( saya lebih suka pendekatan replikasi khusus, karena memberikan saya lebih banyak fleksibilitas )

e. Ubah prosedur penyisipan replikasi tersimpan Anda (biasanya bernama sp_MSins_CurrentTable) untuk juga menyisipkan menggunakanSET 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. Sekarang Anda dapat memulai kembali agen replikasi Anda.

Andrew Bickerton
sumber
1
lol, dibandingkan dengan menggunakan DBCC CHECKIDENT, metode ini sangat banyak pekerjaan.
Jez
@ Jo Anda harus membuat ulang tabel (dengan IDENTITAS) untuk menjalankan CHECKIDENT DBCC ... Sebuah snapshot replikasi akan membuat tabel tanpa kendala IDENTITAS (berdasarkan q Anda, saya akan mengatakan DBID CHECKIDENT menang akan bekerja)
Andrew Bickerton
FYI itu berhasil dan replikasi itu membuat tabel dengan batasan IDENTITY ...
Jez
@ Jo jenis replikasi apa yang Anda setup? (jika Anda mengaturnya sebagai MERGE yang akan terjadi, untuk TRANSAKSIONAL biasanya tidak, meskipun replikasi sangat dapat disesuaikan jika Anda tidak menggunakan GUI)
Andrew Bickerton
Transaksional. Seperti yang saya katakan IDENTITY ada di sana, tetapi nilai identitas saat ini diatur ulang ke nilai seed (1).
Jez