В чем проблема с каскадом внешних ключей с несколькими путями и циклами?

StackOverflow https://stackoverflow.com/questions/1637708

Вопрос

В MSSQL 2005 я только что наткнулся на печально известное сообщение об ошибке:

Введение ограничения ВНЕШНЕГО КЛЮЧА XXX в таблицу YYY может привести к циклам или нескольким каскадным путям.Укажите ПРИ УДАЛЕНИИ НИКАКИХ ДЕЙСТВИЙ или ПРИ ОБНОВЛЕНИИ НИКАКИХ ДЕЙСТВИЙ, или измените другие ограничения ВНЕШНЕГО КЛЮЧА.

Теперь в StackOverflow есть несколько тем об этом сообщении об ошибке, так что у меня уже есть решение (в моем случае мне придется использовать триггеры), но мне любопытно, почему вообще существует такая проблема.

Насколько я понимаю, есть в основном два сценария, которых они хотят избежать - цикл и несколько путей.Цикл - это когда две таблицы имеют каскадные внешние ключи друг к другу.Хорошо, цикл может охватывать и несколько таблиц, но это базовый случай, и его будет легче проанализировать.

Несколько путей было бы, если бы TableA имела внешние ключи для TableB и TableC, а TableB также имела внешний ключ для TableC.Опять же - это минимальный базовый случай.

Я не вижу никаких проблем, которые могли бы возникнуть при удалении или обновлении записи в любой из этих таблиц.Конечно, вам может потребоваться запросить одну и ту же таблицу несколько раз, чтобы увидеть, какие записи нуждаются в обновлении / удалении, но действительно ли это проблема?Это проблема с производительностью?

В других темах SO люди заходят так далеко, что помечают использование каскадов как "рискованный" и заявить , что "решение каскадных путей - сложная проблема".Почему?В чем заключается риск?В чем же проблема?

Это было полезно?

Решение

У вас есть дочерняя таблица с 2 каскадными путями от одного и того же родителя: один " удалить " ;, один " null ".

Что имеет приоритет? Что вы ожидаете после этого? и т.д.

Примечание. Триггер - это код, который может добавить некоторый интеллект или условия к каскаду.

Другие советы

Причина, по которой мы запрещаем использование каскадного удаления, связана с производительностью и блокировкой. Да, это не так плохо, когда вы удаляете одну запись, но рано или поздно вам придется удалить большую группу записей, и ваша база данных остановится.

Если вы удаляете достаточно записей, SQL Server может перерасти в блокировку таблицы, и никто не сможет ничего сделать с таблицей, пока она не будет завершена.

Недавно мы переместили одного из наших клиентов на его собственный сервер. В рамках сделки нам также пришлось удалить все записи этого клиента с нашего исходного сервера. Удаление всей его информации в пакетном режиме (чтобы не вызывать проблем у других пользователей) заняло пару месяцев. Если бы мы настроили каскадное удаление, база данных была бы недоступна для других клиентов в течение длительного времени, так как миллионы записей были удалены за одну транзакцию, а сотни таблиц были заблокированы до завершения транзакции.

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

Еще одна причина избежать каскадного удаления заключается в том, что иногда наличие дочерней записи является достаточной причиной, чтобы не удалять родительскую запись. Например, если у вас есть таблица клиентов, и у этого клиента были заказы в прошлом, вы не захотите удалить его и потерять информацию о фактическом заказе.

Рассмотрим таблицу сотрудников:

CREATE TABLE Employee
(
    EmpID   INTEGER NOT NULL PRIMARY KEY,
    Name    VARCHAR(40) NOT NULL,
    MgrID   INTEGER NOT NULL REFERENCES Employee(EmpID) ON DELETE CASCADE
);

INSERT INTO Employees(     1, "Bill",   1);
INSERT INTO Employees(    23, "Steve",  1);
INSERT INTO Employees(234212, "Helen", 23);

Теперь предположим, что Билл уходит на пенсию:

DELETE FROM Employees WHERE Name = "Bill";

Ооооппппс;всех только что уволили!

[Мы можем поспорить о том, верны ли детали синтаксиса;я думаю, концепция остается в силе.]

Мне кажется, проблема в том, что когда вы делаете один путь "ON DELETE CASCADE" quot; а другой - «УДАЛИТЬ ОГРАНИЧЕНИЕ», или «НЕТ ДЕЙСТВИЯ»; результат (результат) непредсказуем. Это зависит от того, какой триггер удаления (это тоже триггер, но который вам не нужно создавать самостоятельно) будет выполнен первым.

Я согласен с тем, что каскады являются "рискованными" и следует избегать. (Лично я предпочитаю каскадное внесение изменений вручную, а не то, чтобы сервер sql автоматически позаботился о них). Это также потому, что даже если сервер sql удалил миллионы строк, выходные данные все равно будут отображаться как

(затронуты 1 строка)

Я думаю, использовать опцию ON DELETE CASCADE или нет - это вопрос бизнес-модели, которую вы реализуете. Отношения между двумя бизнес-объектами могут быть либо простой «ассоциацией», где оба конца отношения связаны, но в остальном независимыми объектами, жизненный цикл которых отличается и управляется другой логикой. Однако есть также «агрегация». отношения, в которых один объект может фактически рассматриваться как «родительский»; или "владелец" «ребенка» или "подробно" объект. Существует еще более сильное понятие «состав». отношения, где объект существует только как состав из нескольких частей. В «ассоциации» В этом случае вы обычно не объявляете ограничение ON DELETE CASCADE. Однако для агрегатов или композиций ON DELETE CASCADE помогает вам точнее и декларативнее отобразить вашу бизнес-модель в базе данных. Вот почему меня раздражает, что MS SQL Server ограничивает использование этой опции одним каскадным путем. Если я не ошибаюсь, многие другие широко используемые системы баз данных SQL не налагают таких ограничений.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top