Как временно отключить ограничение внешнего ключа в MySQL?


651

Можно ли временно отключить ограничения в MySQL?

У меня есть две модели Django, каждая с ForeignKey к другой. Удаление экземпляров модели возвращает ошибку из-за ограничения ForeignKey:

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()  #a foreign key constraint fails here

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

Можно ли временно отключить ограничения и удалить?


3
Либо я не понимаю, что вы хотите сделать, либо то, что вы пытаетесь сделать, очень, очень, очень уродливо . Даже если вы можете сделать это, вы, вероятно, не должны.
Дариуш

3
Удаление и повторное FK является изменение вашего дб. Вы пытаетесь бросить вызов тем самым ограничениям, которые позволяют системе увидеть какой-то смысл, она не учитывает, что ФК может быть временным явлением, и если бы она это знала, она бы запаниковала.
Грант Томас

1
Странно, что ты пытаешься сделать. Но какую базу данных вы используете?
andrefsp

4
Что если вместо того, чтобы отключить ограничение, вы навсегда изменили его ON DELETE SET NULL? Это могло бы сделать то же самое, и вам не пришлось бы включать и выключать проверку ключа.
dnagirl

1
@dnagirl: так будет лучше. Как я могу это сделать?
июл

Ответы:


1467

Попробуй DISABLE KEYSили

SET FOREIGN_KEY_CHECKS=0;

убедитесь, что

SET FOREIGN_KEY_CHECKS=1;

после.


14
это то, что установлено для MySQL в целом или только для этой сессии?
Типу

28
Я считаю, что это за сессию.
Эндрю Кэмпбелл

13
serverfault.com/questions/291100/… , также обратите внимание, что вы не можете disable keys для Innodb
Pacerier

1
Могу ли я просто отключить FOREIGN_KEY_CHECKS для одной таблицы?
jDub9

@Pacerier Прочитав это, кажется, вы можете, но только для одного сеанса.
Бретт

150

Чтобы отключить ограничение внешнего ключа глобально, выполните следующие действия:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

и не забудьте установить его обратно, когда вы закончите

SET GLOBAL FOREIGN_KEY_CHECKS=1;

ПРЕДУПРЕЖДЕНИЕ. Это следует делать только при выполнении обслуживания в однопользовательском режиме. Как это может привести к несогласованности данных. Например, это будет очень полезно, когда вы загружаете большой объем данных, используя вывод mysqldump.


1
это то, что мне нужно было знать, так что это не очень
хорошая

1
Это сработало для меня после попытки «лучший ответ» не сработало для меня. Возможно, объяснение разницы можно было бы добавить.
hexnet

7
@hexnet Разница в том, что SET FOREIGN_KEY_CHECKSпросто изменяется значение для текущего соединения , а также SET GLOBAL ..изменяется значение для всех соединений , включая будущие соединения. Если вы просто делаете это SET FOREIGN..в одном окне, а затем пытаетесь применить оператор в другом окне (через другое соединение), значение там не изменилось. При GLOBALэтом одна и та же переменная имеет одинаковое значение для обоих соединений.
MatsLindh

Единственное, что могло бы помочь мне при воспроизведении большего дампа (6+ ГБ) <3
Макс

Это не работает для меня. Когда я пытаюсь, я вижу:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
Майк Б

53

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

SET FOREIGN_KEY_CHECKS=0;
TRUNCATE TABLE table;
SET FOREIGN_KEY_CHECKS=1;

25

Вместо того, чтобы отключить ограничение, навсегда измените его на ON DELETE SET NULL. Это выполнит аналогичную вещь, и вам не нужно будет включать и выключать проверку ключа. Вот так:

ALTER TABLE tablename1 DROP FOREIGN KEY fk_name1; //get rid of current constraints
ALTER TABLE tablename2 DROP FOREIGN KEY fk_name2;

ALTER TABLE tablename1 
  ADD FOREIGN KEY (table2_id) 
        REFERENCES table2(id)
        ON DELETE SET NULL  //add back constraint

ALTER TABLE tablename2 
  ADD FOREIGN KEY (table1_id) 
        REFERENCES table1(id)
        ON DELETE SET NULL //add back other constraint

Прочитайте это ( http://dev.mysql.com/doc/refman/5.5/en/alter-table.html ) и это ( http://dev.mysql.com/doc/refman/5.5/en /create-table-foreign-keys.html ).


7
Остерегайтесь изменения таблицы может занять много времени, лучше установить глобальный сервер для FOREIGN_KEY_CHECKS0 и вернуть его после завершения грязной работы. Кроме того, это может заблокировать для записи ваших таблиц.
Аки

Не нарушит ли это ссылку при изменении типа удаленного столбца? (Похоже, мой клиент переименовывает измененную временную таблицу в исходное имя таблицы.)
Сиз Тиммерман

15

Чтобы отключить ограничение внешнего ключа глобально:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

и для активного ограничения внешнего ключа

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

10

Очень простое решение с phpmyadmin:

  • В вашей таблице перейдите на SQLвкладку
  • После того, как вы отредактируете команду SQL, которую вы хотите выполнить, рядом с флажком будет указано GO« Включить проверку внешнего ключа» .
  • Снимите этот флажок и запустите ваш SQL . Он будет автоматически перепроверен после выполнения.

3
Спасибо! Действительно, решение SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;не работало для меня в PHPMyAdmin, потому что я забыл снять флажок «Включить проверки внешнего ключа». В PHPMyAdmin вы можете пропустить эти команды SET и просто снять флажок.
Jan

5

Для меня просто SET FOREIGN_KEY_CHECKS=0;было недостаточно. Я все еще имел com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException.

Я должен был добавить ALTER TABLE myTable DISABLE KEYS;.

Так:

SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE myTable DISABLE KEYS;
DELETE FROM myTable;
ALTER TABLE myTable ENABLE KEYS;
SET FOREIGN_KEY_CHECKS=1;

К вашему сведению, MySQL 5.7 выдает предупреждение, движок InnoDB не имеет этой опции при запуске команды DISABLE KEYS.
jDub9

это сработало, без таблицы изменений это также не сработало для меня
Дэвид

3

Если ключевое поле имеет значение NULL, то вы также можете установить значение NULL, прежде чем пытаться удалить его:

cursor.execute("UPDATE myapp_item SET myapp_style_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed() 

cursor.execute("UPDATE myapp_style SET myapp_item_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

2

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

Это позволит вам удалять строки, даже если есть ограничение ON DELETE.


-2

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

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

Например, предположим, у вас есть веб-сайт для входа в систему студентов, и каждый студент должен зарегистрировать учетную запись в качестве пользователя. У вас есть одна таблица для идентификаторов пользователей, с идентификатором пользователя в качестве первичного ключа; и еще одна таблица для учетных записей студентов с идентификатором студента в виде столбца. Поскольку у каждого учащегося должен быть идентификатор пользователя, имеет смысл сделать идентификатор студента из таблицы учетных записей студентов внешним ключом, который ссылается на идентификатор пользователя первичного ключа в таблице идентификаторов пользователей. Если нет никаких проверок внешнего ключа, у ученика может быть идентификатор ученика и нет идентификатора пользователя, что означает, что ученик может получить учетную запись, не будучи пользователем, что неправильно.

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

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


Правда, всегда есть компромисс.
Pacerier

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

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

3
Это не ответ на вопрос.
Корай Тугай

Обратите внимание, его вопрос заключается в том, как сделать это временно. Это требуется при выполнении определенного обслуживания и импорта данных. Предостережение, конечно, заключается в том, что ваши скрипты импорта становятся ответственными за целостность данных. Затем, позже, когда индексы и ограничения будут снова включены, БД скажет вам, если что-то нарушено.
mcstar
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.