Страница 1 из 1

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

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

Добавлено: 27 дек 2007, 20:09
Merlin
Делают так, чтобы пакет содержал этот порядок.

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

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

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

Добавлено: 28 дек 2007, 15:49
kdv
Поэтому и спрашиваю, какие подходы есть?
сначала делаем странно, а потом пытаемся решить проблемы?

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

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

Добавлено: 28 дек 2007, 17:27
lexas
удаляем в обратном. А двухпроходной это как?

Добавлено: 28 дек 2007, 17:35
Merlin
Гусары! Малчать!

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

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

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

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

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

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

Добавлено: 28 дек 2007, 19:01
WildSery
Как вариант делать интеллектуальный вставщик, который delete/insert превратит в update.

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

Не просто

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

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

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

Навеяно upsert-ом

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

Re: Не просто

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

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

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

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

Добавлено: 28 дек 2007, 22:12
WildSery
lexas писал(а):if (RDB$GET_CONTEXT('rpl') = true) then

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

if (current_user = 'REPLICATOR') then

:-p)

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