Разберите последствие удаления родительской строки, на которую ссылаются дочерние строки через внешний ключ.
Если для внешнего ключа действует поведение RESTRICT или NO ACTION, удаление родительской строки будет отклонено, пока существуют ссылающиеся дочерние строки. При настроенном CASCADE дочерние строки будут удалены автоматически, а при SET NULL их внешний ключ будет обнулён, если столбец допускает NULL.
Внешние ключи появились как механизм поддержания ссылочной целостности в реляционных базах данных. Они решают проблему появления «висячих» дочерних записей, которые ссылаются на уже отсутствующую родительскую сущность.
Без такого ограничения корректность связей зависела бы только от дисциплины прикладного кода. Это особенно рискованно, когда данные изменяются несколькими сервисами, административными скриптами или параллельными транзакциями.
Предположим, заказ связан с клиентом. Если удалить клиента, но оставить его заказы, запросы к данным могут перестать однозначно интерпретироваться: заказ существует, однако его владелец отсутствует.
Неверно выбранное действие при удалении приводит либо к ошибке операции, либо к каскадному удалению большого объёма данных. Поэтому поведение внешнего ключа нужно учитывать при проектировании DELETE, миграций и административных операций.
При выполнении удаления СУБД проверяет дочерние таблицы, содержащие внешний ключ. Если найдены строки, ссылающиеся на удаляемую родительскую строку, применяется действие, заданное для внешнего ключа.
В этом примере удаление клиента с идентификатором 10 завершится ошибкой, если у него есть заказы. Ограничение не удаляет дочерние строки автоматически и не изменяет их значения.
Основные варианты поведения:
NULL во внешний ключ дочерних строк;Название и детали действий могут различаться между СУБД. Нельзя автоматически считать, что отсутствие явного ON DELETE означает каскад: обычно это запрещающее поведение, но точные правила и поддержка отложенных проверок зависят от реализации.
CASCADE удобен для полностью зависимых данных, например строк корзины, существующих только вместе с корзиной. Для заказов, платежей или аудиторских записей чаще выбирают запрет удаления либо мягкое удаление, потому что каскад может уничтожить юридически или аналитически значимую историю.
В CRM потребовалось удалить тестового клиента. У клиента были связанные обращения и заказы. Вариант с ручным удалением дочерних строк оказался опасным: можно было пропустить таблицу и получить ошибку либо нарушить требования к хранению истории.
Рассматривались три решения. CASCADE упрощал очистку, но создавал риск массовой потери данных. SET NULL сохранял обращения, однако лишал их связи с клиентом и требовал допуска NULL. Запрет физического удаления с признаком архивирования сохранял историю, но требовал изменить прикладные запросы.
Выбрали мягкое удаление клиента и запрет физического удаления внешним ключом. В результате история заказов сохранилась, случайный DELETE стал безопасно завершаться ошибкой, а активные отчёты начали явно фильтровать архивные записи.
Оба действия не позволяют нарушить ссылочную целостность. Разница проявляется главным образом при поддержке отложенных ограничений: NO ACTION может проверяться в конце транзакции, тогда как RESTRICT обычно запрещает операцию сразу. Конкретная поддержка зависит от СУБД.
Нет. Если дочерние строки сами являются родителями для других таблиц, каскад может пройти по цепочке зависимостей. Поэтому перед применением CASCADE необходимо оценить граф внешних ключей и фактический объём затрагиваемых данных.
Внешний ключ дочерней таблицы должен допускать NULL. Если на столбце установлен NOT NULL, СУБД не сможет выполнить требуемое обнуление и отклонит удаление родительской строки.