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

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

В любом случае, я решил использовать InnoDB из-за поддержки External Key. Одна вещь, которую я заметил, это то, что она позволяет вам установить On Update и опции Delete для внешних ключей. Может ли кто-нибудь объяснить, где в простом примере можно использовать "Ограничение", "Каскад" и значение "Нуль"?

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

Спасибо

Ответ 1

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

С 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 UPDATE:

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

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

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

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

Edit

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

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

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

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

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

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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