При настройке внешних ключей в SQL Server, при каких обстоятельствах он должен каскадироваться при удалении или обновлении, и каковы причины этого?
Это, вероятно, относится и к другим базам данных.
Больше всего я ищу конкретные примеры каждого сценария, желательно от того, кто их успешно использовал.
sql-server
database-design
foreign-keys
rdbms
cascade
Джоэл Коухорн
источник
источник
sql-server
тег.Ответы:
Резюме того, что я видел до сих пор:
Каскад Удалить
Каскадное обновление
Когда использовать каскадирование
источник
Внешние ключи - лучший способ обеспечить ссылочную целостность базы данных. Избегать каскадов из-за магии - все равно что писать все на ассемблере, потому что вы не доверяете магии, стоящей за компиляторами.
Что плохо, так это неправильное использование внешних ключей, например создание их задом наперед.
Пример Хуана Мануэля является каноническим примером, если вы используете код, есть гораздо больше шансов оставить поддельные DocumentItems в базе данных, которая придет и укусит вас.
Каскадные обновления полезны, например, когда у вас есть ссылки на данные, которые могут измениться, например, первичным ключом таблицы пользователей является комбинация имени и фамилии. Затем вы хотите, чтобы изменения в этой комбинации распространялись туда, где на них ссылаются.
@Aidan, та ясность, на которую вы ссылаетесь, обуславливается высокой стоимостью, вероятность того, что ложные данные останутся в вашей базе данных, а это не мало . Для меня это, как правило, просто незнакомство с БД и неспособность определить, какие ФК существуют, прежде чем работать с БД, которые вызывают этот страх. Или это, или постоянное неправильное использование каскада, использование его там, где сущности не были концептуально связаны, или где вы должны сохранять историю.
источник
Я никогда не использую каскадные удаления.
Если я хочу что-то удалить из базы данных, я хочу явно указать базе данных, что я хочу удалить.
Конечно, они являются функцией, доступной в базе данных, и могут быть случаи, когда их можно использовать, например, если у вас есть таблица 'order' и таблица 'orderItem', вы можете захотеть очистить элементы при удалении порядок.
Мне нравится ясность, которую я получаю от выполнения этого в коде (или хранимой процедуре), а не от «волшебства».
По той же причине я тоже не фанат триггеров.
Стоит заметить, что если вы удалите «заказ», вы получите отчет «На 1 строку затронут», даже если каскадное удаление удалило 50 «элементов OrderItem».
источник
Я много работаю с каскадным удалением.
Приятно знать, что тот, кто работает с базой данных, никогда не оставит нежелательных данных. Если зависимости растут, я просто изменяю ограничения на диаграмме в Management Studio и мне не нужно настраивать sp или dataacces.
Тем не менее, у меня есть 1 проблема с каскадным удалением, и это круговые ссылки. Это часто приводит к частям базы данных, которые не имеют каскадных удалений.
источник
Я много работаю с базой данных и редко нахожу каскадные удаления полезными. Единственный раз, когда я использовал их эффективно, это база данных отчетов, которая обновляется ночными заданиями. Я проверяю, что любые измененные данные импортируются правильно, удаляя все записи верхнего уровня, которые изменились с момента последнего импорта, а затем повторно импортируйте измененные записи и все, что с ними связано. Это избавляет меня от необходимости писать множество сложных удалений, которые смотрят снизу вверх в моей базе данных.
Я не считаю, что каскадное удаление является настолько же плохим, как и триггеры, поскольку они только удаляют данные, у триггеров могут быть самые разные неприятные вещи внутри.
В общем, я вообще избегаю реальных удалений и использую логические удаления (т. Е. Вместо этого используется битовый столбец с именем isDeleted, который устанавливается в значение true).
источник
Один пример - когда у вас есть зависимости между сущностями ... то есть: Document -> DocumentItems (когда вы удаляете Document, DocumentItems не имеет причин для существования)
источник
Используйте каскадное удаление там, где вы хотите удалить запись с FK, если удалена соответствующая запись PK. Другими словами, где запись не имеет смысла без ссылки на запись.
Я считаю, что каскадное удаление полезно, чтобы гарантировать, что мертвые ссылки удаляются по умолчанию, а не вызывают нулевые исключения.
источник
ON Удалить каскад:
Когда вы хотите, чтобы строки в дочерней таблице были удалены Если соответствующая строка удалена в родительской таблице.
Если при каскадном удалении не используется, возникнет ошибка для ссылочной целостности .
Обновление каскада:
Когда вы хотите, чтобы изменение в первичном ключе было обновлено во внешнем ключе
источник
Я слышал о администраторах баз данных и / или «Политике компании», которые запрещают использовать «Каскад при удалении» (и другие) исключительно из-за плохого опыта в прошлом. В одном случае парень написал три триггера, которые в итоге вызвали друг друга. Три дня восстановления привели к полному запрету триггеров, все из-за действий одного idjit.
Конечно, иногда вместо «Каскад при удалении» нужны триггеры, например, когда необходимо сохранить некоторые дочерние данные. Но в других случаях вполне допустимо использовать каскадный метод при удалении. Ключевое преимущество «Каскада при удалении» состоит в том, что он захватывает ВСЕ дочерние элементы; Пользовательская письменная процедура триггера / сохранения может не работать, если она не закодирована правильно.
Я считаю, что Разработчик должен иметь возможность принимать решение, основываясь на том, что такое разработка и что говорит спецификация. Запрет ковра, основанный на плохом опыте, не должен быть критерием; мыслительный процесс «Никогда не используйте» в лучшем случае драконов. Каждый раз необходимо делать суждения и вносить изменения по мере изменения бизнес-модели.
Разве не в этом вся суть развития?
источник
Одной из причин поместить в каскадное удаление (а не делать это в коде) является повышение производительности.
Случай 1: с каскадным удалением
Случай 2: без каскадного удаления
Во-вторых, когда вы добавляете дополнительную дочернюю таблицу с каскадным удалением, код в случае 1 продолжает работать.
Я бы поставил только каскад, в котором семантика отношений является «частью». В противном случае какой-то идиот удалит половину вашей базы данных, когда вы сделаете:
источник
Я стараюсь избегать удалений или обновлений, которые я явно не запрашивал на сервере SQL.
Либо через каскадирование, либо с помощью триггеров. Они имеют тенденцию кусать вас в задницу некоторое время, либо при попытке отследить ошибку, либо при диагностике проблем с производительностью.
Я бы хотел использовать их для обеспечения согласованности не очень больших усилий. Чтобы получить тот же эффект, вам придется использовать хранимые процедуры.
источник
Я, как и все остальные, нахожу, что каскадное удаление действительно только незначительно полезно (это действительно не так много работы для удаления ссылочных данных в других таблицах - если есть много таблиц, вы просто автоматизируете это с помощью скрипта), но действительно раздражает когда кто-то случайно каскадом удаляет некоторые важные данные, которые трудно восстановить.
Единственный случай, в котором я бы использовал, - это если данные в табличной таблице строго контролируются (например, ограничены разрешения) и обновляются или удаляются только через контролируемый процесс (например, обновление программного обеспечения), который был проверен.
источник
Удаление или обновление S, которое удаляет значение внешнего ключа, найденное в некоторых кортежах R, может быть обработано одним из трех способов:
Распространение называется каскадным.
Есть два случая:
‣ Если кортеж в S был удален, удалите кортежи R, которые ссылались на него.
‣ Если кортеж в S был обновлен, обновите значение в R кортежей, которые к нему относятся.
источник
Если вы работаете в системе с множеством разных модулей в разных версиях, это может быть очень полезно, если каскадные удаленные элементы являются частью / принадлежат владельцу PK. В противном случае всем модулям потребовались бы немедленные исправления, чтобы очистить их зависимые элементы перед удалением владельца PK, или отношение внешнего ключа было бы полностью опущено, что может привести к тому, что в системе останутся тонны мусора, если очистка не будет выполнена правильно.
Я только что ввел каскадное удаление для новой таблицы пересечений между двумя уже существующими таблицами (пересечение только для удаления) после того, как каскадное удаление не поощрялось в течение довольно долгого времени. Это также не так уж плохо, если данные будут потеряны.
Однако в таблицах списков, похожих на перечисление, это плохо: кто-то удаляет запись 13 - желтый из таблицы «colors», и все желтые элементы в базе данных удаляются. Кроме того, они иногда обновляются способом delete-all-insert-all, что приводит к полной пропущенной ссылочной целостности. Конечно, это неправильно, но как вы измените сложное программное обеспечение, работающее в течение многих лет, когда внедрение истинной ссылочной целостности может привести к неожиданным побочным эффектам?
Другая проблема заключается в том, что исходные значения внешнего ключа должны сохраняться даже после удаления первичного ключа. Можно создать столбец надгробной плиты и опцию ON DELETE SET NULL для исходного FK, но для этого снова требуются триггеры или специальный код для поддержания избыточного (кроме после удаления PK) значения ключа.
источник
Каскадные удаления чрезвычайно полезны при реализации логических сущностей супертипа и подтипа в физической базе данных.
Когда отдельные таблицы супертипа и подтипа используются для физической реализации супертипов / подтипов (в отличие от свертывания всех атрибутов подтипа в одну физическую таблицу супертипа), существует одно После этого возникает взаимосвязь между этими таблицами и вопросом, как обеспечить 100% синхронизацию первичных ключей между этими таблицами.
Каскадное удаление может быть очень полезным инструментом для:
1) Убедитесь, что удаление записи супертипа также удаляет соответствующую отдельную запись подтипа.
2) Убедитесь, что любое удаление записи подтипа также удаляет запись супертипа. Это достигается путем реализации триггера удаления «вместо» в таблице подтипов, который отправляет и удаляет соответствующую запись супертипа, которая, в свою очередь, каскадно удаляет запись подтипа.
Использование каскадного удаления таким образом гарантирует, что никогда не будет ни одной записи супертипа или подтипа, независимо от того, была ли сначала удалена запись супертипа или сначала запись подтипа.
источник