Обход FK UQ констрейнтов при репликации

Методы, механизмы и инструментарий для репликации

Модератор: kdv

Ответить
lexas
Сообщения: 9
Зарегистрирован: 06 май 2005, 19:40

Обход FK UQ констрейнтов при репликации

Сообщение lexas » 27 дек 2007, 19:45

Как обходят ограничения накладываемые FK UQ констрейнтами, существующими в базе-приемнике, при применении репликационного пакета, который не содержит порядка вставки/удаления/изменений записей, а содержит исключительно список записей, которые добавились, изменились, удалились?

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 27 дек 2007, 20:09

Делают так, чтобы пакет содержал этот порядок.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 28 дек 2007, 13:03

Либо на худой конец порядок накатывания должен быть разбит на таблицы в порядке зависимостей, от мастера к детэйлу.

lexas
Сообщения: 9
Зарегистрирован: 06 май 2005, 19:40

На таблицы разбиты

Сообщение lexas » 28 дек 2007, 15:22

Понятное дело. Другое дело, что возникают тонкости. Если в одной таблице добавляют и удаляют строчку с одинаковыми значениями UQ и разными PK, то в репликационном пакете в таком случае едет информация об удалении по PK и добавлении с новым UQ. Сейчас добавление идёт вперед удаления - возникает нарушение UQ. Если сделать добавление после удаления - будут сыпаться на FK с подчиненных таблиц. Поэтому и спрашиваю, какие подходы есть?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 28 дек 2007, 15:49

Поэтому и спрашиваю, какие подходы есть?
сначала делаем странно, а потом пытаемся решить проблемы?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: На таблицы разбиты

Сообщение WildSery » 28 дек 2007, 16:01

lexas писал(а):Если сделать добавление после удаления - будут сыпаться на FK с подчиненных таблиц.
А удалять - в обратном порядке.
Либо делать двупроходной.

lexas
Сообщения: 9
Зарегистрирован: 06 май 2005, 19:40

Сообщение lexas » 28 дек 2007, 17:27

удаляем в обратном. А двухпроходной это как?

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 28 дек 2007, 17:35

Гусары! Малчать!

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 28 дек 2007, 17:42

Merlin писал(а):Гусары! Малчать!
Собственно, я сперва так и написал, с объяснением, что значит "двухпроходной". Но потом подумал и стёр это предложение.

Автор, это значит, что сперва изменяемые/удаляемые записи направляются на некую служебную запись, типа "ID=0; Name='Неопределено'", а уже во второй проход делается как надо.
Но судя по тому, что и с однопроходным (через обычную Ж :lol: - прим для Merlin) вариантом у тебя сложности, а там ещё сложнее, то не стоит.
Грамотно расставь порядок обработки таблиц, этого должно хватить.

lexas
Сообщения: 9
Зарегистрирован: 06 май 2005, 19:40

Сообщение lexas » 28 дек 2007, 18:04

А если поля, которые формируют FK (которые надо на 0 отправить), входят в свою очередь в состав своего UQ ? При таком перенаправлении будут те UQ ругаться. Или это уже хаос?

у меня сейчас следующий алгоритм: сначала вставляем/обновляем строки в порядке от мастер таблиц к детейлам. Потому удаляем записи (в порядке от детейлов к мастерам). Если в схеме есть циклы, то есть FK смотрит на себя (прямо или опосредственно), то есть вариант обхода, когда в поля FK вставляются NULL, а потом на конечном проходе восстанавливаются оригинальные значения.

У этого подхода есть проблема, когда в один пакет попадает удаление и вставка записи с тем же UQ. Тогда перед удалением в базу пытается вставиться две записи с одинаковым UQ - что ломает процедуру применения пакета.

Если снести нафиг все FK, тогда можно сначала удалять (в принципе пофиг на порядок таблиц), а потом вставлять. Тогда и UQ не будут ругаться. Но FK хочется оставить.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 28 дек 2007, 19:01

Как вариант делать интеллектуальный вставщик, который delete/insert превратит в update.

ЗЫ: Раз у тебя так непросто, то и на репликации стоило бы не экономить, а включать порядок изменения.

lexas
Сообщения: 9
Зарегистрирован: 06 май 2005, 19:40

Не просто

Сообщение lexas » 28 дек 2007, 19:17

С порядком сложно. В общем случае для записи, которую вставляли/меняли на мастере необходимо сохранять не только PK изменившихся записей, но и "промежуточные" (которые были между апдейтами) данные полей входящих в UQ, FK. А тут тогда возникают вопросы (которые быть может алгоритмически проще, но технически не легче) где хранить эти данные?, как и надо ли устраивать свертку обновлений (так как изменений может быть много, а суть изменений сводится к одному апдейту). Так как клиентов репликации много, пока над таким вариантом на думаю.

Как варианты пока вижу:
-перевод FK на триггера, которые можно было бы отключать для транзакции в которой репликатор работает, через например RDB$GET_CONTEXT с последующей проверкой
- defered constraint (которых нет).
- сваливать такие конфликты в таблицу и уже потом руками их разгребать
- получать монопольный доступ к базе. выключать FK, проливать, включать.

Но всё это как-то не совсем гуд.

lexas
Сообщения: 9
Зарегистрирован: 06 май 2005, 19:40

Навеяно upsert-ом

Сообщение lexas » 28 дек 2007, 19:35

Как вариант делать интеллектуальный вставщик, который delete/insert превратит в update.
Если не считать изменение PK и CASCADE UPDATE злом, то замена insert/delete может и покатит. Только все констрейнты на этот PK должны быть каскадными.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Не просто

Сообщение WildSery » 28 дек 2007, 19:43

lexas писал(а):-перевод FK на триггера, которые можно было бы отключать для транзакции в которой репликатор работает, через например RDB$GET_CONTEXT с последующей проверкой
FK на триггерах работать не будет. По-любому.
С RDB$GET_CONTEXT не понял, чего ты хочешь.

lexas
Сообщения: 9
Зарегистрирован: 06 май 2005, 19:40

Сообщение lexas » 28 дек 2007, 19:54

FK на триггерах работать не будет. По-любому.
Будут, но плохенько (ну или не будут.. смотря какие требования к целостности).

RDB$GET_CONTEXT - получать флаг, что в данной транзакции триггера не проверять. т.е. в триггере код типа этого.

if (RDB$GET_CONTEXT('rpl') = true) then
Exit;

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 28 дек 2007, 22:12

lexas писал(а):if (RDB$GET_CONTEXT('rpl') = true) then

Код: Выделить всё

if (current_user = 'REPLICATOR') then

lexas
Сообщения: 9
Зарегистрирован: 06 май 2005, 19:40

:-p)

Сообщение lexas » 28 дек 2007, 22:28

У меня так не получится. Трехзвенка. К БД только SYSDBA. На самом деле это не принципиально. Через current_user, get_context, или current_transaction и таблицу. Суть в том, что FK на триггерах не очень надежно.

Ответить