Робота з діапазонами ідентичності для транзакційної реплікації


9

Я помітив, що коли ви встановлюєте транзакційну реплікацію, SQL Server встановить керування діапазоном ідентичності вручну. Це означає, що в моїй базі даних підписок, коли я намагаюся вставити новий запис у таблицю, ПК - це стовпець ідентичності, він дасть мені помилку і скаже, що намагався вставити ПК "1", "2 "," 3 "і т. Д. Це відбувається тому, що поточне значення ідентичності для всіх стовпців ідентичності підписника повертається до початкового значення (зазвичай 1), а не залишається на тому, що було в видавці.

Я розумію, чому SQL Server робить це - ви повинні залишити таблицю абонентів лише для читання. Однак мій сценарій трохи неортодоксальний - я періодично оновлюю свого підписника за допомогою реплікації, одразу створюю резервну копію цього БД, тоді я хочу зробити кілька оновлень для підписника, щоб НЕ БУДУТЬ бути повернутим до видавця, потім коли я переходжу до оновлення абонента ще раз, я відновлюю його базу даних з попередньої резервної копії та витягую останні оновлення. Оскільки я хочу робити оновлення для абонента між цими оновленнями ("тимчасові дельти", якщо ви хочете), мені потрібен стовпець ідентифікації для роботи, а не для скидання на 1 при реплікуванні.

Я спробував увімкнути автоматичне управління діапазоном ідентичності під час налаштування своєї публікації, але це просто дає мені таку помилку, коли я намагаюся додати таблицю до публікації:

Msg 21231, рівень 16, стан 1, процедура sp_MSrepl_addarticle, рядок 2243
Автоматична підтримка діапазону ідентичності корисна лише для публікацій, які дозволяють оновлювати передплатників.

Чи є спосіб вирішити цю проблему? Я начебто хочу подати цю реплікацію на SQL Server так, ніби вона була лише для читання в кінці підписника, тому що я не планую робити оновлення, які будуть відштовхуватися до видавця , але я хочу робити тимчасові оновлення, які буде стерто до наступної реплікації.

Я також вважав, що реплікація знімка може бути більш підходящим методом, ніж транзакційна реплікація для моєї схеми використання, але проблема полягає в тому, що реплікація знімка вимагає надсилання цілого проклятого БД кожне оновлення; оскільки я планую негайно створити резервну копію БД після останньої реплікації, мені не потрібно було робити цю передачу щоразу; лише зміни, коли минулого разу.


Яку версію SQL Server ви використовуєте? Чи можете ви переглянути таблицю?

2008 р. 2. Я не бачу, як перевизначення таблиці вирішить цю проблему ...
Jez

Я думав про рішення за допомогою SEQUENCE, але це лише для SQL 2012.

2
Is there any way I can get round this problem?Ви повинні встановити стовпець ідентичності як НЕ ДЛЯ ЗАМОВЛЕННЯ, використовуючи sys.sp_identitycolumnforreplication для sql сервера 2005 і новіших версій . Вам навіть не доведеться повторно знімати свої статті, коли ви змінюєте стовпець посвідчення як такий, що не стосується реплікації. Просто не робіть це за допомогою GUI.
Кін Шах

Це вже позначено як не для реплікації. В основному це проблема - SQL Server не копіює інформацію про особистість, тому на абонента він починається з 1.
Jez

Відповіді:


3

Якщо припустити, що Ваш Видавець використовує ідентифікатор int, який починається з 1, ви можете оформити DBCC CHECKIDENT('dbo.mytable', RESEED, -2147483648) його підписника. Потім ви можете використовувати діапазон від -2147483648 до 0, щоб утримувати "тимчасові дельти".


Це рішення, яке я придумав, але це все ще означає, що мій код підключається до видавця та підписника та синхронізує особистість вручну. Я сподівався, що існує більш автоматичний спосіб зробити це.
Jez

Навіщо вам потрібно синхронізувати ідентифікатори вручну? Просто запишіть збережену процедуру в абонента, який запускає контрольну таблицю для кожної таблиці, в яку ви зберігаєте тимчасову дельту, та запустіть її після того, як знімок закінчиться із застосуванням. Агент розподілу буде вставляти зміни в міру того, як вони відбудуться в "реальному" діапазоні ідентичності, а зміни, внесені безпосередньо до абонента, будуть знаходитись у негативному діапазоні.
Ліам Конфрі

1

Що я в кінцевому підсумку робив - це приклеювати транзакційну реплікацію на основі витягування, і з моєю програмою оновити значення ідентичності абонента, щоб вони були такими ж, як і в базі даних публікації одразу після синхронізації (якось я б хотів, щоб агент розповсюдження зробив за власним бажанням ). У псевдо-коді це виглядало приблизно так:

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 полягає в тому, що, хоча за замовчуванням і з усіма моїми таблицями значення ідентичності просто збільшується по одній, воно може бути налаштоване по-різному, тому технічно тут слід дізнатися, як збільшується значення ідентичності на таблиці видавця та збільшується його Точно так же.


0

Мій кращий метод для вирішення цього питання полягає в наступному:

а. Спочатку зупиніть агента реплікації (щоб ви не отримували жодних нових даних у БД підписника)

б. Друге перейменуйте існуючу таблицю

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

c. Створіть свою таблицю за допомогою набору IDENTITY

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

г. Наповніть таблицю (від [BackupTableName]) за допомогою SET IDENTITY_INSERT

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

Після того, як у вашому БД є обмеження IDENTITY , ви можете або зробити власну реплікацію (тобто: змінити вкладку repl rec на SET IDENTITY_INSERT [TableName] ON або встановити прапор NOT FOR REPLICATION на таблиці (що повідомляє сервер SQL, що якщо користувач, що підключається, є агентом реплікації, очікуйте, що значення IDENTITY буде надане) ( я віддаю перевагу підхідному режиму реплікації, оскільки це дає мені більшу гнучкість )

е. Змініть збережену процедуру реплікації вставлення (зазвичай її називають 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
LOL, в порівнянні з використанням DBCC CHECKIDENT, цей метод є величезним обсягом роботи.
Jez

@Jez Вам потрібно буде відтворити таблицю (з IDENTITY), щоб запустити DBCC CHECKIDENT ... Знімок реплікації створить таблицю з обмеженням IDENTITY (виходячи з вашого q, я б сказав, що DBCC CHECKIDENT переміг 't work)
Ендрю Бікертон

FYI, це спрацювало, і тиражування створює таблицю з обмеженням ІДЕНТИЧНОСТІ ...
Jez

@Jez, який тип реплікації ти встановив? (якщо ви встановите його як МЕРЖ, що відбудеться; для TRANSACTIONAL зазвичай це не відбувається, хоча реплікація дуже настроюється, якщо ви не використовуєте графічний інтерфейс)
Ендрю Бікертон,

Трансакційні. Як я вже сказав, IDENTITY є, але поточне значення ідентичності скидається на початкове значення (1).
Jez
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.