Есть ли время, когда мы должны избегать каскадного удаления?

11

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

  1. Итак, является ли каскадное удаление правильным выбором здесь?
  2. Когда не следует использовать каскадный детектор?
Рамеш
источник
3
Никто не может ответить на это, не зная вашего варианта использования. Каскадное удаление всегда может привести к легкому удалению данных. В основном я использую это очень редко, в тех случаях, когда это желаемое поведение. Как правило, это сильно модифицированные таблицы.
Dezso

Ответы:

17

Я обычно опасаюсь каскадного удаления (и других автоматических действий, которые могут сбрасывать / повреждать данные), либо с помощью триггеров, либо ON <something> CASCADE. Такие объекты очень мощные, но также потенциально опасные.

  • Итак, является ли каскадное удаление правильным выбором здесь?

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

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

  • Когда не следует использовать каскадный детектор?

Это не должно использоваться, если вы параноик, как я! Одним из ключевых моментов, которые следует учитывать, являются другие разработчики, которые в настоящее время или могут в будущем работать над вашим кодом / базой данных (отсюда и комментарий выше о документировании любых «скрытых» действий).

По моему опыту, неопытные люди часто используют DELETEзатем повторно INSERTдля обновления строк, особенно когда они действительно хотят выполнить операцию MERGE/ UPSERT(обновить существующие строки и создать новые там, где строки с данным ключом не существует) и СУБД не поддерживает слияние / вставку (или они не знают о ее поддержке). Без каскадных действий это совершенно безопасно (или приведет к ошибке, когда это угрожает целостности данных), но если кто-то сделает это для строк в родительской таблице, где ссылающиеся FK имеютON DELETE CASCADEустановить затем связанные данные будут удалены в результате первоначального удаления и не будут заменены - поэтому данные будут потеряны (не то, что даже если удаление и последующая вставка заключены в явные транзакции, каскад происходит с операцией удаления - он не будет подождите, чтобы увидеть, заменяет ли транзакция строки в родительской таблице в последующих операторах), и каскад может продолжаться через другие корабли отношений (например: удалить старшего супервизора, его команда удаляется каскадом, команды его команд удаляются каскадом, все отслеживаемые записи всех этих людей удаляются каскадом, ...). Без включенного каскадирования вы бы просто получили ошибку, а не потеряли данные.

Дэвид Спиллетт
источник
Будут ли какие-либо последствия для производительности? Как получить блокировку и вручную удалить будет лучше, чем каскад?
Рамеш
Я бы предположил, что будет очень мало различий, при условии, что у вас более ручной процесс, заключенный в явную транзакцию, который вы должны сделать для обеспечения согласованности. Конечно, как на ручной, так и на автоматический (каскадный) методы будут влиять уровни блокировки и изоляции, если учитывать параллелизм.
Дэвид Спиллетт
4

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

Примером, который я использую, чтобы проиллюстрировать этот момент, являются отношения врач / пациент. В одном документе может быть много пациентов. Пациент может быть пациентом, только если у него есть врач. Если документ уходит (покидает практику), то что-то должно случиться с оставшимися пациентами. Одна возможность состоит в том, что они очищаются. Другое - это то, что значение по умолчанию заменяет ссылку на документ или они могут быть удалены из основной таблицы и помещены в другое место. Альтернативно, никакой активности не происходит, и пациенты остаются без изменений, как если бы документ все еще присутствовал. Это зависит от того, что вы хотите сделать.

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

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

Использование каскадного удаления - это вопрос личных предпочтений, например, называть ли таблицы множественными именами или нет (Клиент против Клиентов).

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

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

sa555
источник
Правда, это дает вам больше универсальности, но также вводит «скрытое» поведение, означающее, что вам нужно иметь дополнительную документацию для этих sps (чтобы ppl знал, какие бизнес-действия требуют какого sp) другим способом было бы ограничить пользователей sql только способен выполнять эти sps и вообще не выполнять другие "простые" вставки / обновления.
DrCopyPaste