Когда использовать «ОБНОВЛЕНИЕ КАСКАДА»

420

Я регулярно использую «ON DELETE CASCADE», но никогда не пользуюсь «ON UPDATE CASCADE», так как не уверен, в какой ситуации это будет полезно.

Ради обсуждения, давайте посмотрим код.

CREATE TABLE parent (
    id INT NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (id)
);

CREATE TABLE child (
    id INT NOT NULL AUTO_INCREMENT, parent_id INT,
    INDEX par_ind (parent_id),
    FOREIGN KEY (parent_id)
        REFERENCES parent(id)
        ON DELETE CASCADE
);

Для "ON DELETE CASCADE", если родительский элемент с idудален, запись в дочернем элементе с parent_id = parent.idбудет автоматически удалена. Это должно быть без проблем.

  1. Это означает, что «ON UPDATE CASCADE» будет делать то же самое при idобновлении родительского элемента?

  2. Если (1) имеет значение true, это означает, что нет необходимости использовать «ON UPDATE CASCADE», если parent.idон не обновляется (или никогда не будет обновляться), например, когда он установлен AUTO_INCREMENTили всегда установлен TIMESTAMP. Это правильно?

  3. Если (2) неверно, в какой другой ситуации мы должны использовать «ОБНОВЛЕНИЕ КАСКАДА»?

  4. Что если я (по какой-то причине) обновлю что- child.parent_idто, что не существует, будет ли оно автоматически удалено?

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

Пожалуйста, пролите немного света.

NawaMan
источник
1
См. Также: stackoverflow.com/questions/6894162/…
Xiè Jìléi

Ответы:

468

Это правда, что если ваш первичный ключ представляет собой просто значение идентификатора, которое автоматически увеличивается, у вас не будет реального использования ON UPDATE CASCADE.

Однако предположим, что ваш первичный ключ - это 10-значный штрих-код UPC, и в связи с расширением его необходимо заменить на 13-значный штрих-код UPC. В этом случае ON UPDATE CASCADE позволит вам изменить значение первичного ключа, и любые таблицы, имеющие ссылки на внешний ключ, будут соответственно изменены.

В отношении # 4, если вы измените дочерний идентификатор на то, чего нет в родительской таблице (и у вас есть ссылочная целостность), вы должны получить ошибку внешнего ключа.

C-Pound Guru
источник
6
Просто пришлось использовать ON UPDATE CASCADEсебя для обновления первичных ключей в старой таблице, которая не использует автоинкрементный ключ
BlueRaja - Danny Pflughoeft
86
  1. Да, это означает, что, например, если вы UPDATE parent SET id = 20 WHERE id = 10все дети, parent_id из 10 также будет обновлен до 20

  2. Если вы не обновите поле, на которое ссылается внешний ключ, этот параметр не требуется

  3. Не могу думать ни о каком другом использовании.

  4. Вы не можете сделать это, так как ограничение внешнего ключа потерпит неудачу.

Zed
источник
29

Я думаю, что вы в значительной степени прибили очки!

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

Зед отметил , что если вы используете естественный ключ (например, обычное поле из таблицы базы данных) в качестве первичного ключа, то могут возникнуть ситуации, когда вам необходимо обновить свои первичные ключи. Другим недавним примером может быть ISBN (международные стандартные номера книг), который не так давно изменился с 10 до 13 цифр + символов.

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

Итак, в конце концов: если ваш первичный ключ никогда не изменяется, тогда вам никогда не понадобится ON UPDATE CASCADEпредложение.

Марк

marc_s
источник
Что такое «искусственно генерируемые системой» ключи? UUID , ?
HPWD
1
@HPWD: просто «искусственный» ключ (значение, которое не основано или не получено из ваших фактических данных), который генерируется системой - это может быть GUID, или INT, или BIGINT - или что-то действительно - не не имеет значения. Дело в том, что это значение никоим образом не связано с вашими собственными фактическими данными, и система автоматически генерирует это значение для вас.
marc_s
@ marc-s спасибо, что нашли время написать это. Ваш ответ имел смысл.
HPWD
2
По моему мнению, таблица из одного столбца с естественными ключами является хорошей и чистой альтернативой перечислениям (по крайней мере, в разновидностях MySQL DB). В качестве примера рассмотрим таблицу colorsсо строками blue, purple, yellow, и стол productsс product_colorколонки, будучи FK'ed к colorsстолу. Это ограничивает выбор, например, перечисление, но в отличие от целочисленного с автоматическим приращением, для получения имени цвета не требуется объединение. В таком случае, on update cascadeэто хорошая идея, если вы решили, что вместо этого purpleследует вызвать violet.
okdewit
18

Несколько дней назад у меня была проблема с триггерами, и я понял, что это ON UPDATE CASCADEможет быть полезно. Взгляните на этот пример (PostgreSQL):

CREATE TABLE club
(
    key SERIAL PRIMARY KEY,
    name TEXT UNIQUE
);

CREATE TABLE band
(
    key SERIAL PRIMARY KEY,
    name TEXT UNIQUE
);

CREATE TABLE concert
(
    key SERIAL PRIMARY KEY,
    club_name TEXT REFERENCES club(name) ON UPDATE CASCADE,
    band_name TEXT REFERENCES band(name) ON UPDATE CASCADE,
    concert_date DATE
);

В моем выпуске я должен был определить некоторые дополнительные операции (триггер) для обновления таблицы концерта. Эти операции должны были изменить club_name и band_name. Я не смог этого сделать из-за ссылки. Я не мог изменить концерт и затем иметь дело со столами клуба и группы. Я также не мог сделать это по-другому. ON UPDATE CASCADEбыл ключом к решению проблемы.

Ариэль Грабиджас
источник
3
Хороший комментарий Я считаю, что каскад обновлений также полезен, в любом случае вы должны изменить свой идентификатор. Я также согласен с другими, что это изменение не должно быть типичным. Например, в случае, когда вы цитируете, я думаю, что при больших объемах данных, возможно, связывание внешних ключей с использованием текстовых полей может не привести к самой высокой производительности ядра базы данных. Заметьте, что если внешнее отношение в концертном столе использует club.SERIAL и band.SERIAL, изменения в имени не повлияют на отношение между таблицами. Тем не менее, я считаю, что ОБНОВЛЕНИЕ CASCADE является отличным инструментом для решения чрезвычайных ситуаций. С уважением
David L
4
Это сомнительный дизайн, который служит довольно надуманным примером. Какой смысл держать две SERIALколонки в clubи в bandкачестве первичных ключей , если вы ссылаетесь nameс вместо первичного ключа каждой таблицы?
см
Короче говоря, это полезно, если вы дублируете поле из другой таблицы и вам нужно, чтобы оно было актуальным.
Камил Томшик
4

Мой комментарий в основном относится к пункту № 3: при каких обстоятельствах применяется ON UPDATE CASCADE, если мы предполагаем, что родительский ключ не подлежит обновлению? Вот один случай.

Я имею дело со сценарием репликации, в котором несколько спутниковых баз данных должны быть объединены с главной. Каждый спутник генерирует данные в одних и тех же таблицах, поэтому объединение таблиц с ведущим ведет к нарушению ограничения уникальности. Я пытаюсь использовать ON UPDATE CASCADE как часть решения, в котором я заново увеличиваю ключи при каждом слиянии. ОБНОВЛЕНИЕ CASCADE должно упростить этот процесс за счет автоматизации части процесса.

ted.strauss
источник
3

Это отличный вопрос, у меня вчера был тот же вопрос. Я думал об этой проблеме, в частности, ПОИСК, если существовало что-то вроде «ОБНОВЛЕНИЕ КАСКАДА», и, к счастью, разработчики SQL тоже думали об этом. Я согласен с Ted.strauss, и я также прокомментировал дело Норана.

Когда я использовал это? Как указал Тед, когда вы обрабатываете несколько баз данных одновременно, и изменение в одной из них, в одной таблице, имеет какое-либо воспроизведение в том, что Тед называет «спутниковой базой данных», невозможно сохранить с самой оригинальной ID, и по любой причине вам нужно создать новый, в случае, если вы не можете обновить данные в старом (например, из-за разрешений, или если вы ищете скорость в случае, который настолько эфемерен, что не заслуживает абсолютного и полного уважения к общим правилам нормализации, просто потому что это будет очень недолгая утилита)

Итак, я согласен в двух моментах:

(А.) Да, во многих случаях лучший дизайн может избежать этого; НО

(B.) В случае миграции, репликации баз данных или решения чрезвычайных ситуаций, это КРАСИВЫЙ ИНСТРУМЕНТ, который, к счастью, был там, когда я отправился на поиск, если он существует.

Дэвид Л
источник