Ограничения внешнего ключа: когда использовать при обновлении и удалении

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

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

например, скажем, у меня user таблица, которая включает в себя userID. И скажите, что у меня есть таблица сообщений message который является много-ко-многим, который имеет 2 внешних ключа (которые ссылаются на тот же первичный ключ, userID на user таблица). Является ли установка параметров ON Update и On Delete полезной в этом случае? Если да, то какой мне выбрать? Если это не хороший пример, не могли бы вы привести хороший пример, чтобы проиллюстрировать, как они могут быть полезны?

спасибо

3 ответов


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

С 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;

давайте посмотрим на НА статья:

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

и теперь УДАЛИТЬ сторона:

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

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

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

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

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

==> смотрите ниже последнее редактирование, все движется по этому домену

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

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

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

12/2017-обновления изменения о MySQL:

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


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

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

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

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


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

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