Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Оператор MERGE и транзакционная репликация - будьте бдительны.  [new]
Zubov56
Member

Откуда:
Сообщений: 30
Нашел вот такую интересность:

Есть транзакционная репликация. Если в реплицируемой таблице изменить запись оператором UPDATE, то на подписчике, как и полагается, будет вызвана процедура, привязанная к UPDATE. А вот если такое же изменение произвести оператором MERGE (т.е. when matched ... then update ...), то на издателе это будет действительно UPDATE (это видно по триггерам), а на подписчике последовательно вызовутся процедуры для DELETE и INSERT.

Самое печальное, если на подписчике эта запись не может удалиться, скажем, по внешнему ключу, то репликация валится с ошибкой.

Вывод неутешителен: лучше не использовать MERGE на реплицируемых таблицах. А тому, кто уже использует - перелопачивать код :(
21 июн 13, 18:59    [14467778]     Ответить | Цитировать Сообщить модератору
 Re: Оператор MERGE и транзакционная репликация - будьте бдительны.  [new]
Zubov56
Member

Откуда:
Сообщений: 30
Да, забыл: издатель - 2008 enterprise, подписчик - 2008 web.
21 июн 13, 19:01    [14467783]     Ответить | Цитировать Сообщить модератору
 Re: Оператор MERGE и транзакционная репликация - будьте бдительны.  [new]
Crimean
Member

Откуда:
Сообщений: 13147
если я не сильно путаю, то и обычный UPDATE может подписчику доставиться как DELETE + INSERT
а форины и триггера на подписчике - зло большое имхо и тогда уже реплицируйте вызовы хранимок, что ли
21 июн 13, 19:56    [14467890]     Ответить | Цитировать Сообщить модератору
 Re: Оператор MERGE и транзакционная репликация - будьте бдительны.  [new]
invm
Member

Откуда: Москва
Сообщений: 9646
Такое поведение давно описано - UPDATE Statements May be Replicated as DELETE/INSERT Pairs. Хотя документ относится к версиям до 2005 включительно, поведение не изменилось и в последующих версиях.
21 июн 13, 20:52    [14468020]     Ответить | Цитировать Сообщить модератору
 Re: Оператор MERGE и транзакционная репликация - будьте бдительны.  [new]
invm
Member

Откуда: Москва
Сообщений: 9646
Самый простой способ борьбы - помечать FK на подписчике как not for replication.
21 июн 13, 20:54    [14468022]     Ответить | Цитировать Сообщить модератору
 Re: Оператор MERGE и транзакционная репликация - будьте бдительны.  [new]
Zubov56
Member

Откуда:
Сообщений: 30
Crimean
если я не сильно путаю, то и обычный UPDATE может подписчику доставиться как DELETE + INSERT

invm
Такое поведение давно описано - UPDATE Statements May be Replicated as DELETE/INSERT Pairs.


Спасибо, кэпы )
Эта штука тянется как минимум с 2000, и речь совсем не о ней. Я говорю о разнице между UPDATE и MERGE.


Crimean
а форины и триггера на подписчике - зло большое имхо и тогда уже реплицируйте вызовы хранимок, что ли

invm
Самый простой способ борьбы - помечать FK на подписчике как not for replication.


"Форины" на подписчике не большее зло, чем любой констрейн в любой базе - это вопрос организации системы. Не думая их херить (или выставлять not for replication) - это, конечно, просто, только чревато иногда.

Привел я их только в качестве иллюстрации, как можно поиметь проблему на ровном вроде месте. Можно еще нафантазировать - например, у дистрибушен-агента нет прав на delete.

А реплицировать хранимки, кстати, тоже не так просто: https://www.sql.ru/forum/937229/oshibka-pri-vypolnenii-sp-droparticle
24 июн 13, 19:58    [14476399]     Ответить | Цитировать Сообщить модератору
 Re: Оператор MERGE и транзакционная репликация - будьте бдительны.  [new]
invm
Member

Откуда: Москва
Сообщений: 9646
Zubov56
Я говорю о разнице между UPDATE и MERGE.
Транзакционная реплика ведь совсем просто и без изысков работает -- что есть в журнале транзакций, то и уходит подписчикам.
Поэтому не могли бы вы привести репро, которое при изменении одних и тех же данных через update дает в журнале modify, а через merge будет delete/insert?
24 июн 13, 20:36    [14476451]     Ответить | Цитировать Сообщить модератору
 Re: Оператор MERGE и транзакционная репликация - будьте бдительны.  [new]
Zubov56
Member

Откуда:
Сообщений: 30
invm
Транзакционная реплика ведь совсем просто и без изысков работает -- что есть в журнале транзакций, то и уходит подписчикам.
Поэтому не могли бы вы привести репро, которое при изменении одних и тех же данных через update дает в журнале modify, а через merge будет delete/insert?


Уважаемый invm, я хорошо представляю себе, как работает транзакционная репликация. Я не прошу меня спасать, просто делюсь любопытным наблюдением, может кому-нибудь пригодится. Сам бы знал раньше - какие-то вещи делал бы по-другому.

А репро - легко: )
create table Table1 (id int primary key, val int)
go
insert Table1 (id,val) select 1,1
go

-- Отреплицируется update
update Table1 set val=2 where id=1

-- Отреплицируется delete/insert
merge into Table1 as trg
using (select 1 as id, 2 as val) as src (id, val) on trg.id = src.id 
when matched and trg.val<>src.val then update set val = src.val;
25 июн 13, 12:49    [14479405]     Ответить | Цитировать Сообщить модератору
 Re: Оператор MERGE и транзакционная репликация - будьте бдительны.  [new]
invm
Member

Откуда: Москва
Сообщений: 9646
Zubov56
Я не прошу меня спасать
А я и не спасаю, - мне тоже любопытно.
Покажите, пожалуйста, результат выполнения:
create table dbo.Table1 (id int primary key, val int)
go
insert dbo.Table1 (id,val) select 1,1
go

begin tran Test1;
-- Отреплицируется update
update dbo.Table1 set val=2 where id=1

declare @tid varchar(30);
select @tid = [Transaction ID] from fn_dblog(null, null) where [Transaction Name] = 'Test1';
select [Current LSN], Operation, Context, AllocUnitName from fn_dblog(null, null) where [Transaction ID] = @tid;

rollback;
go

begin tran Test2;
-- Отреплицируется delete/insert
merge into dbo.Table1 as trg
using (select 1 as id, 2 as val) as src (id, val) on trg.id = src.id 
when matched and trg.val<>src.val then update set val = src.val;

declare @tid varchar(30);
select @tid = [Transaction ID] from fn_dblog(null, null) where [Transaction Name] = 'Test2';
select [Current LSN], Operation, Context, AllocUnitName from fn_dblog(null, null) where [Transaction ID] = @tid;

rollback;
go

drop table dbo.Table1;
go
25 июн 13, 13:29    [14479789]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить