Когда / Почему использовать каскадирование в SQL Server?

при настройке внешних ключей в SQL Server, при каких обстоятельствах вы должны каскадировать его на удаление или обновление, и каковы причины этого?

Это, вероятно, относится и к другим базам данных.

больше всего я ищу конкретные примеры каждого сценария, желательно от кого-то, кто успешно их использовал.

15 ответов


резюме того, что я видел до сих пор:

  • некоторые люди вообще не любят каскадирование.

Каскадное Удаление

  • Cascade Delete может иметь смысл, когда семантика отношений может включать в себя эксклюзив "часть" описание. Например, запись OrderLine является частью родительского заказа, и OrderLines никогда не будут совместно использоваться несколькими заказами. Если заказ исчез, в OrderLine должны как ну, и без заказа будет проблемой.
  • каноническим примером для Cascade Delete является SomeObject и SomeObjectItems, где нет никакого смысла для записи элементов когда-либо существовать без соответствующей основной записи.
  • вы должны не используйте Cascade Delete, если вы сохраняете историю или используете "мягкое / логическое удаление", где вы устанавливаете только удаленный битовый столбец в 1/true.

Каскад Update

  • каскадное обновление может иметь смысл, когда вы используете реальный ключ, а не суррогатный ключ (столбец identity/autoincrement) в таблицах.
  • канонический пример для каскадного обновления - это когда у вас есть изменяемый внешний ключ, например имя пользователя, которое можно изменить.
  • вы должны не используйте каскадное обновление с ключами, которые являются столбцами Identity/autoincrement.
  • каскадное обновление лучше всего использовать в сочетании с уникальным ограничение.

Когда Использовать Каскадирование

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

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

плохо неправильное использование внешних ключей, например, создание их назад.

пример Хуана Мануэля является каноническим примером, если вы используете код, есть гораздо больше шансов оставить ложные DocumentItems в базе данных, которые придут и укусить вас.

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

@Aidan, эта ясность, на которую вы ссылаетесь, имеет высокую стоимость, шанс оставить ложные данные в вашей базе данных, которая не маленький. Для меня это обычно просто отсутствие знакомство с БД и невозможность найти, какие FKs находятся на месте, прежде чем работать с БД, которые способствуют этому страху. Либо это, либо постоянное злоупотребление cascade, используя его там, где сущности не были концептуально связаны, или где вы должны сохранить историю.


Я никогда не использую каскадные удаления.

Если я хочу что-то удалить из базы данных, я хочу явно сказать базе данных, что я хочу вынуть.

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

Мне нравится ясность, которую я получаю от этого в коде (или сохраненном процедура), а не "волшебство".

по той же причине я тоже не поклонник триггеров.

Что-то заметить, что если вы удалите "заказ", вы получите отчет "1 строка затронута", даже если каскадное удаление удалило 50 " orderItem.


Я много работаю с каскадными удалениями.

приятно знать, что тот, кто работает против базы данных, может никогда не оставлять ненужных данных. Если зависимости растут, я просто изменяю ограничения в диаграмме в Management Studio, и мне не нужно настраивать sp или dataacces.

тем не менее, у меня есть 1 проблема с каскадными удалениями и круговыми ссылками. Это часто приводит к частям базы данных, которые не имеют каскадных удалений.


одним из примеров является наличие зависимостей между сущностями... ie: Document - > DocumentItems (при удалении документа у DocumentItems нет причин для существования)


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

Я не считаю, что каскадные удаления так же плохи, как триггеры, поскольку они удаляют только данные, триггеры могут иметь все виды неприятных вещей внутри.

вообще я избегаю реальных удалений вообще и использую логические удаления (т. е. имея битовый столбец с именем isDeleted, который получает значение true).


используйте cascade delete, где вы хотите удалить запись с FK, если ее ссылка на запись PK была удалена. Другими словами, когда запись бессмысленна без ссылки на запись.

Я нахожу cascade delete полезным, чтобы гарантировать, что мертвые ссылки удаляются по умолчанию, а не вызывают исключения null.


на Удалить Каскад:

Если вы хотите строки в дочерней таблице должны быть удалены если соответствующая строка удаляется в родительской таблице.

Если на каскадное удаление не используется, тогда ошибка будет вызвана для целостность.

на каскаде обновления:

Если вы хотите изменение первичного ключа для обновления в внешний ключ


одна из причин поставить каскадное удаление (а не делать это в коде), чтобы улучшить производительность.

Случай 1: с каскадом удалить

 DELETE FROM table WHERE SomeDate < 7 years ago;

случай 2: Без каскадного удаления

 FOR EACH R IN (SELECT FROM table WHERE SomeDate < 7 years ago) LOOP
   DELETE FROM ChildTable WHERE tableId = R.tableId;
   DELETE FROM table WHERE tableId = R.tableid;
   /* More child tables here */
 NEXT

во-вторых, когда вы добавляете дополнительную дочернюю таблицу с каскадным удалением, код в случае 1 продолжает работать.

Я бы только поставил Каскад, где семантика отношений является "частью". Иначе какой-нибудь идиот удалит половину твоего база данных, когда вы делаете:

DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'

Я стараюсь избегать удалений или обновлений, которые я явно не запрашивал в SQL server.

либо через каскадирование, либо через использование триггеров. Они, как правило, кусают вас в задницу некоторое время вниз по линии, либо при попытке отследить ошибку или при диагностике проблем с производительностью.

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


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

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


Я слышал о DBAs и / или" политике компании", которые запрещают использование" on Delete Cascade " (и других) исключительно из-за плохого опыта в прошлом. В одном случае парень написал три триггера, которые в конечном итоге позвонили друг другу. Три дня на восстановление привели к полному запрету на триггеры, все из-за действий одного идиота.

конечно, иногда триггеры необходимы вместо "on Delete cascade", например, когда некоторые дочерние данные должны быть сохранены. Но в других случаях ее идеально подходит для использования метода on Delete cascade. Ключевым преимуществом "on Delete cascade" является то, что он захватывает все дочерние элементы; пользовательская записанная процедура запуска/хранения может не быть, если она не закодирована правильно.

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

разве это не то, что развития вообще?


удаление или обновление до S, которое удаляет значение внешнего ключа, найденное в некоторых кортежах R, можно обработать одним из трех способов:

  1. отказ
  2. распространение
  3. недействительным.

распространение называется каскадным.

есть два случая:

‣ Если Кортеж в S был удален, удалите R кортежей, которые ссылались на него.

‣ Если Кортеж в S был обновлен, обновите значение в R кортежи, которые относятся к нему.


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

Я только что представил cascade delete для нового таблица пересечений между двумя уже существующими таблицами (только пересечение для удаления), после каскадного удаления, в течение некоторого времени не поощрялась. Также неплохо, если данные теряются.

Это, однако, плохо для таблиц перечислений: кто - то удаляет запись 13-yellow из таблицы "цвета", и все желтые элементы в базе данных удаляются. Кроме того, они иногда обновляются способом удаления всех вставок, что приводит к тому, что ссылочная целостность полностью опущена. Из конечно, это неправильно, но как вы измените сложное программное обеспечение, которое работает в течение многих лет, с введением истинной ссылочной целостности, рискуя неожиданными побочными эффектами?

другая проблема заключается в том, что исходные значения внешнего ключа сохраняются даже после удаления первичного ключа. Можно создать столбец надгробия и параметр ON DELETE SET NULL для исходного FK, но для этого снова требуются триггеры или конкретный код для поддержания избыточности (за исключением PK deletion) значение ключа.


каскадные удаления чрезвычайно полезны при реализации логических сущностей супер-типа и подтипа в физической базе данных.

когда отдельные таблицы супертипа и подтипа используются для физической реализации супертипов/подтипов (в отличие от свертывания всех атрибутов подтипа в одну физическую таблицу супертипа), между этими таблицами существует связь "один к одному", и проблема заключается в том, как синхронизировать первичные ключи на 100% между этими таблицами таблицы.

каскадные удаления могут быть очень полезным инструментом для:

1) Убедитесь, что удаление записи супер-типа также удаляет соответствующую запись одного подтипа.

2) Убедитесь, что любое удаление записи подтипа также удаляет запись супертипа. Это достигается путем реализации триггера удаления" вместо " в таблице подтипа, который идет и удаляет соответствующую запись супертипа, которая, в свою очередь, каскадом удаляет подтип запись.

использование каскадных удалений таким образом гарантирует, что не существует бесхозных записей супер-типа или подтипа, независимо от того, удаляете ли Вы запись супер-типа первой или запись подтипа первой.