Добро пожаловать в форум, Guest >> Войти | Регистрация | Поиск | Правила | | В избранное | Подписаться | ||
Все форумы / Microsoft SQL Server |
![]() ![]() |
Zubov56 Member Откуда: Сообщений: 30 |
Нашел вот такую интересность: Есть транзакционная репликация. Если в реплицируемой таблице изменить запись оператором UPDATE, то на подписчике, как и полагается, будет вызвана процедура, привязанная к UPDATE. А вот если такое же изменение произвести оператором MERGE (т.е. when matched ... then update ...), то на издателе это будет действительно UPDATE (это видно по триггерам), а на подписчике последовательно вызовутся процедуры для DELETE и INSERT. Самое печальное, если на подписчике эта запись не может удалиться, скажем, по внешнему ключу, то репликация валится с ошибкой. Вывод неутешителен: лучше не использовать MERGE на реплицируемых таблицах. А тому, кто уже использует - перелопачивать код :( |
21 июн 13, 18:59 [14467778] Ответить | Цитировать Сообщить модератору |
Zubov56 Member Откуда: Сообщений: 30 |
Да, забыл: издатель - 2008 enterprise, подписчик - 2008 web. |
21 июн 13, 19:01 [14467783] Ответить | Цитировать Сообщить модератору |
Crimean Member Откуда: Сообщений: 13147 |
если я не сильно путаю, то и обычный UPDATE может подписчику доставиться как DELETE + INSERT а форины и триггера на подписчике - зло большое имхо и тогда уже реплицируйте вызовы хранимок, что ли |
21 июн 13, 19:56 [14467890] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9646 |
Такое поведение давно описано - UPDATE Statements May be Replicated as DELETE/INSERT Pairs. Хотя документ относится к версиям до 2005 включительно, поведение не изменилось и в последующих версиях. |
21 июн 13, 20:52 [14468020] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9646 |
Самый простой способ борьбы - помечать FK на подписчике как not for replication. |
21 июн 13, 20:54 [14468022] Ответить | Цитировать Сообщить модератору |
Zubov56 Member Откуда: Сообщений: 30 |
Спасибо, кэпы ) Эта штука тянется как минимум с 2000, и речь совсем не о ней. Я говорю о разнице между UPDATE и MERGE.
"Форины" на подписчике не большее зло, чем любой констрейн в любой базе - это вопрос организации системы. Не думая их херить (или выставлять not for replication) - это, конечно, просто, только чревато иногда. Привел я их только в качестве иллюстрации, как можно поиметь проблему на ровном вроде месте. Можно еще нафантазировать - например, у дистрибушен-агента нет прав на delete. А реплицировать хранимки, кстати, тоже не так просто: https://www.sql.ru/forum/937229/oshibka-pri-vypolnenii-sp-droparticle |
||||||||
24 июн 13, 19:58 [14476399] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9646 |
Поэтому не могли бы вы привести репро, которое при изменении одних и тех же данных через update дает в журнале modify, а через merge будет delete/insert? |
||
24 июн 13, 20:36 [14476451] Ответить | Цитировать Сообщить модератору |
Zubov56 Member Откуда: Сообщений: 30 |
Уважаемый 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] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9646 |
Покажите, пожалуйста, результат выполнения: 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 | ![]() |