Вопрос

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

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

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

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

Решение

Краткое изложение того, что я видел на данный момент:

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

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

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

Каскадное обновление

  • Каскадное обновление может иметь смысл, если вы используете в таблицах реальный ключ, а не суррогатный ключ (столбец идентификации/автоинкремента).
  • Канонический пример Cascade Update — это случай, когда у вас есть изменяемый внешний ключ, например имя пользователя, которое можно изменить.
  • Вам следует нет используйте каскадное обновление с ключами, которые являются столбцами идентификаторов/автоинкремента.
  • Каскадное обновление лучше всего использовать в сочетании с ограничением уникальности.

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

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

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

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

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

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

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

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

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

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

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

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

По той же причине я не фанат триггеров.

Следует отметить, что если вы удалите «заказ», вы получите отчет «Затронута 1 строка», даже если каскадное удаление удалило 50 «orderItem».

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

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

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

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

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

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

Одним из примеров является ситуация, когда у вас есть зависимости между сущностями...то есть:Документ -> DocumentItems (когда вы удаляете документ, у DocumentItems нет причин для существования)

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

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

ВКЛ. Удалить каскад:

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

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

ВКЛ. Каскад обновлений:

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

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

Дело 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-сервере.

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

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

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

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

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

  1. Отказ
  2. Распространение
  3. обнуление.

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

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

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

‣ Если кортеж в S был обновлен, обновите значение в кортежах R, которые ссылаются на него.

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

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

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

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

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

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

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

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

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

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

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