Ограничения внешнего ключа: когда использовать ON UPDATE и ON DELETE - PullRequest
172 голосов
/ 17 июля 2011

Я проектирую свою схему базы данных, используя MySQL Workbench, что довольно круто, потому что вы можете создавать диаграммы и конвертировать их: P

В любом случае, я решил использовать InnoDB из-за поддержки внешнего ключа. Однако я заметил одну вещь: она позволяет вам устанавливать параметры «При обновлении» и «Удалить» для внешних ключей. Может кто-нибудь объяснить, где в простом примере можно использовать «Restrict», «Cascade» и set null?

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

Спасибо

Ответы [ 3 ]

447 голосов
/ 17 июля 2011

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

В MySQL у вас нет расширенных ограничений, как в postgreSQL, но по крайней мереограничения внешнего ключа довольно продвинуты.

Мы возьмем пример, таблицу компании с таблицей пользователей, содержащей людей из этой компании

CREATE TABLE COMPANY (
     company_id INT NOT NULL,
     company_name VARCHAR(50),
     PRIMARY KEY (company_id)
) ENGINE=INNODB;

CREATE TABLE USER (
     user_id INT, 
     user_name VARCHAR(50), 
     company_id INT,
     INDEX company_id_idx (company_id),
     FOREIGN KEY (company_id) REFERENCES COMPANY (company_id) ON...
) ENGINE=INNODB;

Давайте посмотрим на ONОБНОВЛЕНИЕ предложение:

  • НА ОГРАНИЧЕНИИ ОБНОВЛЕНИЯ : по умолчанию : если вы попытаетесь обновить company_id в таблице COMPANY, двигатель отклонит операциюесли хотя бы один ПОЛЬЗОВАТЕЛЬ хотя бы ссылается на эту компанию.
  • ОБНОВЛЕНИЕ НЕТ ДЕЙСТВИЯ : аналогично ОГРАНИЧЕНИЮ.
  • ОБНОВЛЕНИЕ ОБНОВЛЕНИЯ : самый лучший обычно : если вы обновите company_id в строке таблицы COMPANY, механизм обновит его соответствующим образом во всех строках USER, ссылающихся на эту COMPANY (но триггеры не активированы на USER tв состоянии, предупреждение).Движок будет отслеживать изменения для вас, это хорошо.
  • ON UPDATE SET NULL : если вы обновите company_id в строке таблицы COMPANY, механизм установит для соответствующих USER company_id значение NULL (должен быть доступен в поле USER company_id).Я не вижу ничего интересного в обновлении, но я могу ошибаться.

А теперь на стороне ON DELETE :

  • ON DELETE RESTRICT : значение по умолчанию : если вы попытаетесь удалить ID_идентификатора компании в таблице COMPANY, механизм отклонит операцию, если один пользователь USER хотя бы ссылается на эту компанию, может сохранитьваша жизнь.
  • НА УДАЛИТЬ НЕТ ДЕЙСТВИЙ : то же, что ОГРАНИЧЕНИЕ
  • НА УДАЛИТЬ КАСКАД : опасно : если вы удаляетеСтрока компании в таблице COMPANY, которую удалит двигатель, а также связанные ПОЛЬЗОВАТЕЛИ.Это опасно, но может использоваться для автоматической очистки вторичных таблиц (поэтому это может быть что-то, что вы хотите, но совершенно точно не для примера COMPANY <-> USER)
  • ON DELETE SET NULL : пригоршня : если вы удалите строку КОМПАНИЯ, соответствующие ПОЛЬЗОВАТЕЛИ автоматически будут связаны с NULL.Если значение Null является для пользователей без компании, это может быть хорошим поведением, например, может быть, вам нужно сохранить пользователей в вашем приложении в качестве авторов некоторого контента, но удаление компании не является для вас проблемой.

обычно мои значения по умолчанию: ВКЛ УДАЛИТЬ ОГРАНИЧЕНИЕ НА ОБНОВЛЕНИЕ КАСКАДА .с некоторыми ON DELETE CASCADE для таблиц дорожек (журналы - не все журналы - и тому подобное) и ON DELETE SET NULL, когда главная таблица является «простым атрибутом» для таблицы, содержащей внешний ключ, как таблица JOB дляТаблица USER.

Редактировать

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

Триггеры MySQL активируются толькодля изменений, внесенных в таблицы с помощью операторов SQL.Они не активируются ни для изменений в представлениях, ни для изменений в таблицах, сделанных API, которые не передают операторы SQL на MySQL Server

==> См. Ниже последнего редактирования, в этом домене происходят изменения

Триггеры не активируются действиями внешнего ключа.

И я не думаю, что это когда-нибудь исправят. Ограничения внешнего ключа управляются хранилищем InnoDb, а триггеры - движком MySQL SQL. Оба разделены. Innodb - единственное хранилище с управлением ограничениями, может быть, однажды они добавят триггеры непосредственно в механизм хранения, а может и нет.

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

12/2017-Обновление этого редактирования о MySQL:

Как заявил @IstiaqueAhmed в комментариях, ситуация на эту тему изменилась. Поэтому перейдите по ссылке и проверьте реальную актуальную ситуацию (которая может снова измениться в будущем).

2 голосов
/ 17 июля 2011

Добавление к ответу @MarkR. Следует отметить, что многие PHP-фреймворки с ORM не распознают или не используют расширенную настройку БД (внешние ключи, каскадное удаление, уникальные ограничения), и это может привести к неожиданному поведению.

Например, если вы удалите запись с помощью ORM, а ваш DELETE CASCADE удалит записи в связанных таблицах, попытка ORM удалить эти связанные записи (часто автоматически) приведет к ошибке.

1 голос
/ 17 июля 2011

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

Подумайте, как ваше приложение должно реагировать на различные случаи.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...