Работа с диапазонами идентификаторов для репликации транзакций


9

Я заметил, что когда вы настраиваете репликацию транзакций, SQL Server устанавливает ручное управление диапазоном идентификаторов. Это означает, что в моей базе данных подписки, когда я пытаюсь вставить новую запись в таблицу, PK которой является столбцом идентификаторов, он выдаст мне ошибку и скажет, что он попытался вставить PK "1", "2 "," 3 "и т. Д. Это связано с тем, что текущее значение идентификатора для всех столбцов идентификатора на подписчике возвращается к начальному значению (обычно 1) вместо того, чтобы оставаться на том же уровне, что и на издателе.

Я понимаю, почему SQL Server делает это - вы должны оставить таблицу подписчиков только для чтения. Тем не менее, мой сценарий немного неортодоксален - я время от времени обновляю своего подписчика посредством репликации, делаю немедленное резервное копирование этой БД, затем я хочу сделать некоторые обновления для подписчика, которые НЕ БУДУТ возвращены издателю, а затем когда я снова обновляю подписчика, я восстанавливаю его базу данных из более ранней резервной копии и извлекаю последние обновления. Поскольку я хочу сделать обновления для подписчика между этими обновлениями («временные разницы», если хотите), мне нужен столбец идентификаторов для работы, а не для сброса в 1 при репликации.

Я попытался включить автоматическое управление диапазоном идентификаторов при настройке своей публикации, но при попытке добавить таблицу в публикацию у меня просто появляется следующая ошибка:

Сообщение 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 и выше. Вам даже не нужно повторно снимать ваши статьи, когда вы изменяете столбец идентификаторов, а не для репликации. Просто не делайте этого с помощью графического интерфейса.
Кин Шах

Это уже помечено как не для репликации. Это в основном проблема - SQL Server не копирует идентификационную информацию, поэтому на подписчике он начинается с 1.
Jez

Ответы:


3

Предполагая, что ваш издатель использует идентификацию int, начинающуюся с 1, вы можете выдавать DBCC CHECKIDENT('dbo.mytable', RESEED, -2147483648) подписчику. Затем вы можете использовать диапазон от -2147483648 до 0 для хранения ваших «временных дельт».


Это решение, которое я придумал, но оно все еще означает, что мой код соединяется с издателем и подписчиком и синхронизирует идентификаторы вручную. Я надеялся, что есть более автоматический способ сделать это.
Еж

Зачем вам нужно синхронизировать удостоверения вручную? Просто напишите хранимую процедуру на подписчике, который запускает checkident для каждой таблицы, в которой вы храните временные дельты, и запускайте ее после завершения применения снимка. Агент распространения будет вставлять изменения, когда они происходят, в «реальный» диапазон идентификаторов, а изменения, внесенные непосредственно подписчику, будут находиться в отрицательном диапазоне.
Лиам Конфри

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

с. Пересоздайте свою таблицу с установленным 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 на 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

е. Теперь вы можете перезапустить ваш агент репликации.


1
LOL, по сравнению с использованием DBCC CHECKIDENT, этот метод представляет собой огромный объем работы.
Еж

@Jez вам нужно будет воссоздать таблицу (с IDENTITY), чтобы запустить DBCC CHECKIDENT ... Снимок репликации создаст таблицу без ограничения IDENTITY (основываясь на вашем q, я бы сказал, DBCC CHECKIDENT победил не работает)
Эндрю Бикертон

К вашему сведению, это сработало, и репликация создает таблицу с ограничением IDENTITY ...
Jez

@Jez, какой тип репликации вы настроили? (если вы установите его как MERGE, что произойдет, для TRANSACTIONAL это обычно не происходит, хотя репликация очень настраиваема, если вы не используете GUI)
Эндрю Бикертон,

Транзакционный. Как я уже сказал, IDENTITY существует, но текущее значение идентификатора сбрасывается до начального значения (1).
Еж
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.