Разница между каскадом при удалении и каскадом при обновлении в mysql

46

У меня есть две таблицы в MySQL database- parent, child. Я пытаюсь добавить ссылки на внешние ключи в мою дочернюю таблицу на основе родительской таблицы. Есть ли существенная разница между ON UPDATE CASCADEиON DELETE CASCADE

Мой родительский стол

CREATE TABLE parent (
    id INT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;

Мой вопрос: в чем разница между следующими SQL-запросами.

  1. ON DELETE CASCADE

    CREATE TABLE child (
        id INT, 
        parent_id INT,
        INDEX par_ind (parent_id),
        FOREIGN KEY (parent_id) 
            REFERENCES parent(id)
            ON DELETE CASCADE
    ) ENGINE=INNODB;
    
  2. ON UPDATE CASCADE

    CREATE TABLE child (
        id INT, 
        parent_id INT,
        INDEX par_ind (parent_id),
        FOREIGN KEY (parent_id) 
            REFERENCES parent(id)
            ON UPDATE CASCADE
    ) ENGINE=INNODB;
    
  3. ON UPDATE CASCADE ON DELETE CASCADE

    CREATE TABLE child (
            id INT, 
            parent_id INT,
            INDEX par_ind (parent_id),
            FOREIGN KEY (parent_id) 
                REFERENCES parent(id)
                ON UPDATE CASCADE ON DELETE CASCADE
        ) ENGINE=INNODB;
    

Есть ли ошибки в запросах? Что означают эти запросы (1,2 и 3) ?? Они такие же ???

Одинокий волк
источник
1
пс <придираться> для полноты картины , что вы говорите о выше являются DDL (Data Definition Language) заявления , а не запросы. Запрос обычно считается DML (язык выбора данных SELECT, INSERT, UPDATE, DELETE) </ nitpick>
Vérace
Еще раз ps для полноты, я задавался вопросом, что было по умолчанию. Поэтому я создал ребенка без обновлений или удалений. Затем происходит то, что вы не можете ни обновить, ни удалить родителя, у которого есть зависимый ребенок. Это имеет смысл, однако MySQL не всегда является моделью этой конкретной характеристики :-)
Vérace

Ответы:

64

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

В стандарте SQL 2003 есть 5 различных ссылочных действий:

  1. CASCADE
  2. RESTRICT
  3. БЕЗДЕЙСТВИЕ
  4. SET NULL
  5. УСТАНОВИТЬ ПО УМОЛЧАНИЮ

Чтобы ответить на вопрос:

  1. CASCADE

    • ON DELETE CASCADEозначает, что если родительская запись удалена, любые дочерние записи также будут удалены. На мой взгляд, это не очень хорошая идея. Вы должны отслеживать все данные, которые когда-либо были в базе данных, хотя это можно сделать с помощью TRIGGERs. (Тем не менее, см. Предостережение в комментариях ниже).

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

    • ON UPDATE CASCADE ON DELETE CASCADEозначает, что если вы UPDATE ИЛИ DELETE родитель, изменения каскадно относятся к ребенку. Это эквивалентно ANDрезультатам первых двух утверждений.

  2. RESTRICT

    • RESTRICTозначает, что любая попытка удалить и / или обновить родителя приведет к ошибке. Это поведение по умолчанию в том случае, если ссылочное действие не указано явно.

      Для ON DELETEили ON UPDATEне указано, действие по умолчанию всегда RESTRICT`.

  3. БЕЗДЕЙСТВИЕ

    • NO ACTION: С ручной . Ключевое слово из стандартного SQL. В MySQL эквивалентно RESTRICT. MySQL Server отклоняет операцию удаления или обновления для родительской таблицы, если в ссылочной таблице есть соответствующее значение внешнего ключа. Некоторые системы баз данных имеют отложенные проверки и NO ACTIONявляются отложенными проверками. В MySQL ограничения внешнего ключа проверяются немедленно, так NO ACTIONже, как и RESTRICT.
  4. SET NULL

    • SET NULL- опять из руководства. Удалите или обновите строку из родительской таблицы и установите для столбца или столбца внешнего ключа в дочерней таблице значение NULL. ИМХО, это не лучшая идея, в первую очередь потому, что нет способа «путешествовать во времени», то есть заглянуть в дочерние таблицы и связать записи с NULLs с соответствующей родительской записью, либо CASCADEиспользовать TRIGGERs для заполнения таблиц журналов для отслеживания. изменения (но см. комментарии).
  5. УСТАНОВИТЬ ПО УМОЛЧАНИЮ

    • SET DEFAULT, Еще одна (потенциально очень полезная) часть стандарта SQL, которую MySQL не потрудился реализовать! Позволяет разработчику указать значение, для которого необходимо установить столбцы внешнего ключа в UPDATE или DELETE. InnoDB и NDB отклонят определения таблиц с SET DEFAULTпредложением.

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

Verace
источник
8
Мне нравится ваш полный ответ, однако я не согласен с этим утверждением. «Вы должны отслеживать все данные, которые когда-либо были в базе данных» - это действительно зависит от структуры и целей базы данных. Например, определение рецепта (я не говорю о еде - больше похоже на конфигурации системы), когда определение рецепта удаляется, нет смысла сохранять связанных потомков этого рецепта - что просто раздувает БД без причины. Также рабочие таблицы для машинных систем - мне больше не нужны данные; обработать и избавиться от него. Кроме этого ваш ответ фантастический.
StixO
2
похоже на @StixO Мне больше нравится этот ответ, но я не согласен с изменением первичного ключа. Определенно есть проекты, где это было бы плохой идеей, но когда вы попадаете в распределенную базу данных, может быть очень желательно, чтобы первичные ключи могли быть переназначены без потери идентичности записи.
Гарет Клаборн
«На мой взгляд, это не очень хорошая идея. Вы должны отслеживать все данные, которые когда-либо были в базе данных». - Не уверен, что понимаю вашу мысль. Если вы каскадируете «при удалении», то вы уже решили, что вам нужно что-то удалить. Если вы решите никогда ничего не удалять, ничего не будет каскадно. Преимущество его наличия в том, что в вашем приложении вы можете быть уверены, что, когда вы ищете запись с иностранным идентификатором, вы знаете, что она будет там, и не будет никаких строк-сирот, раздувающих вашу базу данных, если вы решите удалить что-то.
Джефф Райан
Логика здесь довольно ошибочна в некоторых местах, и тем более в нашем новом мире GDPR. Я согласен с тем, что если первичные ключи меняются, это может быть признаком чего-то неправильного.
Чак Ле Батт
Если вы меняете ПЕРВИЧНЫЕ КЛЮЧИ с какой-либо регулярностью (или даже вообще!), Значит, что-то не так с вашим дизайном. Вы имеете в виду, что ON UPDATE CASCADE изменяет значение ключа или имя ключа?
Биллаль Бегерадж
8

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

Если вы выполните:

UPDATE parent SET id = -1 WHERE id = 1;

И есть по крайней мере одна запись childс parent_id = 11) потерпит неудачу; в случаях 2) и 3) все записи с parent_id = 1 обновляются до parent_id = -1.

Если вы выполните:

DELETE FROM parent WHERE id = 1;

И есть по крайней мере одна запись childс parent_id = 1, 2) потерпит неудачу; в случаях 1) и 3) все записи с parent_id = 1удаляются.

3) синтаксически правильно.

Полную документацию можно найти в руководстве .

jynus
источник
6

У меня недостаточно репутации, чтобы комментировать предыдущие ответы. Поэтому я подумал, что немного уточню.

1) ON DELETE CASCADE означает, что если родительская запись удалена, то все ссылки на дочерние записи также удаляются. ON UPDATE по умолчанию - RESTRICT, что означает, что UPDATE родительской записи завершится ошибкой.

2) Действие ON DELETE по умолчанию равно RESTRICT, что означает, что DELETE для родительской записи завершится ошибкой. ON UPDATE CASCADE обновит все ссылающиеся дочерние записи при обновлении родительской записи.

3) См. Действия КАСКАДА в 1) и 2) выше.

Об использовании идентификаторов родительских записей в качестве внешних ключей (в дочерних таблицах) - опыт подсказывает: а) если идентификаторы являются автоматически генерируемыми порядковыми номерами, то НЕ используйте их в качестве внешних ключей. Вместо этого используйте другой уникальный родительский ключ. б) если идентификаторы являются GUID, то их можно использовать в качестве внешних ключей. Вы увидите мудрость этого предложения при экспорте и импорте записей или копировании записей в другую базу данных. Слишком сложно работать с автоматически генерируемыми порядковыми номерами во время переноса данных, когда на них ссылаются как на внешние ключи.

гр
источник