Comment désactiver temporairement une contrainte de clé étrangère dans MySQL?


651

Est-il possible de désactiver temporairement les contraintes dans MySQL?

J'ai deux modèles Django, chacun avec une clé étrangère à l'autre. La suppression d'instances d'un modèle renvoie une erreur en raison de la contrainte 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()

Est-il possible de désactiver temporairement les contraintes et de les supprimer quand même?


3
Soit je ne comprends pas ce que vous voulez faire, soit ce que vous essayez de faire est très, très, très laid . Même si vous pouvez le faire, vous ne devriez probablement pas.
Dariusz

3
Laissant tomber et réappliquer une FK est en train de changer votre base de données. Vous essayez de défier les contraintes mêmes qui permettent au système de voir un certain sens, il n'a aucun égard qu'un FK pourrait être une chose temporaire, et s'il le savait, il paniquerait.
Grant Thomas

1
C'est étrange ce que vous essayez de faire. Mais quelle base de données utilisez-vous?
andrefsp

4
Et si, au lieu de désactiver votre contrainte, vous la modifiiez définitivement ON DELETE SET NULL? Cela accomplirait une chose similaire et vous n'auriez pas à activer et désactiver la vérification des clés.
dnagirl

1
@dnagirl: ce serait mieux, en effet. Comment puis je faire ça?
jul

Réponses:


1467

Essayez DISABLE KEYSou

SET FOREIGN_KEY_CHECKS=0;

assurez-vous de

SET FOREIGN_KEY_CHECKS=1;

après.


14
est-ce quelque chose qui est défini pour mysql dans son ensemble ou juste cette session?
tipu

28
Je pense que c'est par session.
Andrew Campbell


1
Puis-je simplement désactiver FOREIGN_KEY_CHECKS pour une seule table?
jDub9

@Pacerier De la lecture de cela, il semble que vous pouvez, mais seulement pour une seule session.
Brett

150

Pour désactiver globalement la contrainte de clé étrangère, procédez comme suit:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

et n'oubliez pas de le remettre en place lorsque vous avez terminé

SET GLOBAL FOREIGN_KEY_CHECKS=1;

AVERTISSEMENT: vous ne devez effectuer cette opération que lorsque vous effectuez une maintenance en mode utilisateur unique. Comme cela pourrait entraîner une incohérence des données. Par exemple, cela sera très utile lorsque vous téléchargez une grande quantité de données à l'aide d'une sortie mysqldump.


1
c'est ce que je devais savoir, donc ce n'est pas une bonne pratique, mais cette réponse des gars devrait être plus élevée ...
ftrotter

1
Cela a fonctionné pour moi après avoir essayé la «meilleure réponse» n'a pas fonctionné pour moi. Peut-être qu'une explication de la différence pourrait être ajoutée.
hexnet

7
@hexnet La différence est que juste SET FOREIGN_KEY_CHECKSchange la valeur de la connexion actuelle , tandis que SET GLOBAL ..change la valeur de toutes les connexions , y compris les futures connexions. Si vous ne faites que SET FOREIGN..dans une fenêtre, puis essayez d'appliquer l'instruction dans une fenêtre différente (via une connexion différente), la valeur n'a pas changé à cet endroit. Avec GLOBAL, la même variable a la même valeur pour les deux connexions.
MatsLindh

La seule chose qui pourrait m'aider lors de la lecture d'un plus grand vidage (6+ Go) <3
Max

Ça ne marche pas pour moi. Quand j'essaye, je vois:ERROR 1228 (HY000): Variable 'foreign_key_checks' is a SESSION variable and can't be used with SET GLOBAL
Mike B

53

Normalement, je ne désactive les contraintes de clé étrangère que lorsque je veux tronquer une table, et comme je reviens toujours à cette réponse, c'est pour moi à l'avenir:

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

25

Au lieu de désactiver votre contrainte, modifiez-la en permanence sur ON DELETE SET NULL. Cela accomplira une chose similaire et vous n'auriez pas à activer et désactiver la vérification des clés. Ainsi:

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

Lisez ceci ( http://dev.mysql.com/doc/refman/5.5/en/alter-table.html ) et ceci ( http://dev.mysql.com/doc/refman/5.5/en /create-table-foreign-keys.html ).


7
Attention, la modification de la table peut prendre du temps, mieux vaut régler le serveur global FOREIGN_KEY_CHECKSà 0 et le remettre une fois le sale boulot terminé. En outre, il peut se verrouiller pour l'écriture de vos tables.
Aki

Cela ne brisera-t-il pas la référence lors de la modification du type de colonne distante? (Il semble que mon client renomme une table temporaire modifiée au nom de la table d'origine.)
Cees Timmerman

15

Pour désactiver globalement la contrainte de clé étrangère:

SET GLOBAL FOREIGN_KEY_CHECKS = 0;

et pour la contrainte de clé étrangère active

SET GLOBAL FOREIGN_KEY_CHECKS = 1;

10

Une solution très simple avec phpmyadmin:

  • Dans votre tableau, allez dans l' SQLonglet
  • Après avoir modifié la commande SQL que vous souhaitez exécuter, il y a une case à cocher à côté GO, intitulée « Activer les vérifications de clé étrangère» .
  • Décochez cette case et exécutez votre SQL . Il sera automatiquement revérifié après l'exécution.

3
Merci! En effet, la solution SET FOREIGN_KEY_CHECKS=0; ..... SET FOREIGN_KEY_CHECKS=1;n'a pas fonctionné pour moi dans PHPMyAdmin car j'ai oublié de décocher la case "Activer la vérification des clés étrangères". Dans PHPMyAdmin, vous pouvez ignorer ces commandes SET et décochez simplement la case.
Jan

5

Pour moi, ce SET FOREIGN_KEY_CHECKS=0;n'était pas suffisant. J'avais encore un com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException.

Je devais ajouter ALTER TABLE myTable DISABLE KEYS;.

Donc:

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

Pour info, mySQL 5.7 lance un avertissement, le moteur InnoDB n'a pas cette option lors de l'exécution de la commande DISABLE KEYS.
jDub9

cela a fonctionné, sans la table alter, cela n'a pas fonctionné non plus pour moi
David Kabii

3

Si le champ clé est nullable, vous pouvez également définir la valeur sur null avant de tenter de le supprimer:

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

Dans phpMyAdmin, vous pouvez sélectionner plusieurs lignes, puis cliquer sur l'action de suppression. Vous allez entrer dans un écran qui répertorie les requêtes de suppression, vous pouvez décocher la vérification de la clé étrangère et cliquer sur Oui pour les exécuter.

Cela vous permettra de supprimer des lignes même s'il existe une contrainte de restriction ON DELETE.


-2

Ce n'est pas une bonne idée de définir une contrainte de clé étrangère à 0, car si vous le faites, votre base de données ne garantirait pas qu'elle ne viole pas l'intégrité référentielle. Cela pourrait conduire à des données inexactes, trompeuses ou incomplètes.

Vous créez une clé étrangère pour une raison: parce que toutes les valeurs de la colonne enfant doivent être identiques à une valeur de la colonne parent. S'il n'y a pas de contraintes de clé étrangère, une ligne enfant peut avoir une valeur qui n'est pas dans la ligne parent, ce qui entraînerait des données inexactes.

Par exemple, supposons que vous ayez un site Web pour que les étudiants se connectent et que chaque étudiant doit créer un compte en tant qu'utilisateur. Vous avez une table pour les ID utilisateur, avec l'ID utilisateur comme clé primaire; et un autre tableau pour les comptes étudiants, avec l'ID étudiant en colonne. Étant donné que chaque étudiant doit avoir un ID utilisateur, il serait judicieux de faire de l'ID étudiant de la table des comptes étudiants une clé étrangère qui fait référence à l'ID utilisateur de la clé primaire dans la table des ID utilisateur. S'il n'y a pas de vérification de clé étrangère, un étudiant pourrait finir par avoir un identifiant étudiant et aucun identifiant utilisateur, ce qui signifie qu'un étudiant peut obtenir un compte sans être un utilisateur, ce qui est faux.

Imaginez si cela arrive à une grande quantité de données. C'est pourquoi vous avez besoin de la vérification de la clé étrangère.

Il est préférable de déterminer la cause de l'erreur. Vous essayez probablement de supprimer d'une ligne parent sans supprimer d'une ligne enfant. Essayez de supprimer de la ligne enfant avant de supprimer de la ligne parent.


Certes, il y a toujours un compromis.
Pacerier

21
Personne ne dit de le faire fonctionner comme ça pour toujours. Vous désactivez les contraintes, chargez en masse certaines données et les réactivez. Pas grave, les gens le font tout le temps.
bwawok

elle est nécessaire pour les importations en vrac, pour les performances au moins, elle est très courante. parfois, vous avez juste besoin de restaurer les données, vous pouvez alors faire vos vérifications.
Firas Abd Alrahman

3
Ce n'est pas une réponse à la question.
Koray Tugay

Remarque, sa question est de savoir comment procéder temporairement. Cela est nécessaire lors de certaines opérations de maintenance et d'importations de données. La mise en garde est bien sûr que vos scripts d'importation deviennent responsables de l'intégrité des données. Plus tard, lorsque les index et les contraintes seront réactivés, la base de données vous dira si quelque chose est cassé.
mcstar
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.