SQL Server: как игнорировать ссылочную целостность до COMMIT? - PullRequest
4 голосов
/ 27 февраля 2010

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

Поскольку вся операция происходит в транзакции 1 , я хочу, чтобы SQL Server игнорировал ошибки ссылочной целостности, пока я не вызову COMMIT TRANSACTION.

Например 2 :

   Table: Turboencabulators         Table: Marselvanes
   =========================        =======================
PK TurboencabulatorID int    /-> PK MarselvaneID       int
^  MarselvanesID      int --/       HasGrammeter       bit
|                                   PantametricFan     varchar(50)
+-------------------------------    TurboencabulatorID int

Если я попытаюсь вставить турбоэнкабулятор в новую таблицу, он потерпит неудачу, если marselvane уже там. Отмена ордера имеет ту же проблему.

При попытке удалить старые строки я не могу удалить одну, пока другая не будет удалена.

Я попытался создать n -фазную систему, где все строки вставляются с любыми столбцами, для которых ограничение внешнего ключа установлено на null . Затем я обновляю все вставленные строки, помещая правильные пропущенные значения. Затем, чтобы удалить исходные строки, я обнуляю все столбцы, на которые влияет FK , затем удаляю фактические строки. 3

Что я действительно предпочитаю, так это просто выполнять мои операции с T-SQL, и чтобы SQL Server не сообщал мне, пока я не попытаюсь вызвать commit.

Примечания

1 1037 * распределены * 2 надуманный гипотетический
3 что я больше не делаю

Ответы [ 2 ]

11 голосов
/ 27 февраля 2010

вы можете использовать ...

ALTER TABLE whatever_table NOCHECK CONSTRAINT ALL 

чтобы удалить проверку ограничений перед началом

и когда закончите, включите его снова ...

ALTER TABLE whatever_table CHECK CONSTRAINT ALL 

это то, что я бы сделал в любом случае.

-don

2 голосов
/ 27 февраля 2010

Представьте, как бы вы это реализовали.

Если решение по внешнему ключу будет отложено до фиксации транзакции, то при фиксации потребуется выполнить все операции поиска / проверки / каскада, которые не выполнялись во время вставки / удаления / обновления. Подумайте, что на самом деле означает ограничение FK: ваш план выполнения вставки «аннотируется» дополнительной операцией для проверки и применения ограничения FK. Если вы отложите ограничение, дополнительная логика в плане запроса должна быть не связана с моментом выполнения и помещена в некоторый контекст транзакции, чтобы он выполнялся во время принятия. Внезапная фиксация превращается из операции «короткая транзакция зафиксирована в журнале» в операцию, которая выполняет все, что было пропущено во время реальной транзакции. Хуже всего то, что ограничение может потерпеть неудачу, и подумать , как приложение обработает ошибку ? Если в момент выполнения вставки введено ограничение, приложение может отловить ошибку и предпринять корректирующие действия: оно точно знает, что не удалось. Но если вы отложите это до фиксации, вы попытаетесь зафиксировать и поймать исключение, теперь вам нужно как-то выяснить, из-за исключения, что не удалось. Подумайте, насколько сложна жизнь разработчиков приложений в этом случае.

Вторая причина, по которой это не сработало, заключается в том, что вы все еще не решили проблему. У вас есть таблица A с ограничением FK в B. Вы начинаете транзакцию, вставляете в B, затем вставляете в A, затем удаляете из A, затем удаляете из B, затем фиксируете. Все операции удовлетворяли FK в момент их возникновения, база данных удовлетворяла FK во время фиксации. Тем не менее, если вы отложите проверку ограничений, они будут терпеть неудачу во время фиксации !!

Так что я бы сказал, что ссылочная целостность работает нормально, как есть, но она разработана для каскадной иерархии, свободной от циклов. Как и многие структуры данных CS и алгоритмы, он ломается, когда вводятся циклы. Лучшим решением было бы проанализировать схему и посмотреть, действительно ли циклы неизбежны. Если не считать этого, вставка NULL и обновление пост-вставки - лучшее решение.

К сожалению, отключение ограничения и включение возврата - это большая проблема: нет, повторное включение должно проверять каждую строку в таблице, чтобы проверить ограничение, и будет длиться вечно. В противном случае ограничение помечается как «ненадежное» в метаданных базы данных, и оптимизатор в основном игнорирует его (все равно будет применено, но вы не получите от него преимуществ оптимизации плана).

...