Mysql
 sql >> Base de données >  >> RDS >> Mysql

Contraintes de clé étrangère :quand utiliser ON UPDATE et ON DELETE

N'hésitez pas à mettre des contraintes sur la base de données. Vous serez sûr d'avoir une base de données cohérente, et c'est l'une des bonnes raisons d'utiliser une base de données. Surtout si vous avez plusieurs applications qui le demandent (ou une seule application mais avec un mode direct et un mode batch utilisant différentes sources).

Avec MySQL, vous n'avez pas de contraintes avancées comme vous en auriez dans postgreSQL, mais au moins les contraintes de clé étrangère sont assez avancées.

Prenons un exemple, une table société avec une table utilisateur contenant des personnes de cette société

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;

Regardons le ON UPDATE clause :

  • ON LIMITER LA MISE À JOUR :la valeur par défaut :si vous essayez de mettre à jour un company_id dans la table COMPANY le moteur rejettera l'opération si au moins un USER établit un lien sur cette société.
  • LORS DE LA MISE À JOUR AUCUNE ACTION :identique à RESTRICT.
  • EN CASCADE DE MISE À JOUR :le meilleur en général :si vous mettez à jour un company_id dans une ligne de la table COMPANY le moteur le mettra à jour en conséquence sur toutes les lignes USER référençant cette COMPANY (mais pas de triggers activés sur la table USER, attention). Le moteur suivra les changements pour vous, c'est bien.
  • LORS DE LA MISE À JOUR SET NULL  :si vous mettez à jour un company_id dans une ligne de la table COMPANY, le moteur définira les USERs company_id associés sur NULL (devrait être disponible dans le champ USER company_id). Je ne vois rien d'intéressant à faire avec cela dans une mise à jour, mais je peux me tromper.

Et maintenant sur ON DELETE côté :

  • ON SUPPRIMER RESTREINDRE :la valeur par défaut :si vous essayez de supprimer un identifiant company_id dans la table COMPANY le moteur rejettera l'opération si un USER au moins lie sur cette société, peut vous sauver la vie.
  • LORS DE LA SUPPRESSION AUCUNE ACTION :identique à RESTRICT
  • SUPPRIMER EN CASCADE :dangereux :si vous supprimez une ligne de société dans la table COMPANY, le moteur supprimera également les USERs associés. Ceci est dangereux mais peut être utilisé pour effectuer des nettoyages automatiques sur des tables secondaires (cela peut donc être quelque chose que vous voulez, mais certainement pas pour un exemple COMPANY<->USER)
  • ON DELETE SET NULL :une poignée :si vous supprimez une ligne COMPANY, les USERs associés auront automatiquement la relation avec NULL. Si Null est votre valeur pour les utilisateurs sans entreprise, cela peut être un bon comportement. Par exemple, vous devez peut-être conserver les utilisateurs de votre application en tant qu'auteurs de certains contenus, mais la suppression de l'entreprise ne vous pose aucun problème.

généralement ma valeur par défaut est :ON DELETE RESTRICT ON UPDATE CASCADE . avec quelques ON DELETE CASCADE pour les tables de suivi (journaux -- pas tous les journaux --, des choses comme ça) et ON DELETE SET NULL lorsque la table maître est un 'simple attribut' pour la table contenant la clé étrangère, comme une table JOB pour la table USER.

Modifier

Ça fait longtemps que je n'ai pas écrit ça. Maintenant, je pense que je devrais ajouter un avertissement important. MySQL a une grande limitation documentée avec les cascades. Les cascades ne déclenchent pas de déclencheurs . Donc, si vous étiez suffisamment confiant dans ce moteur pour utiliser des déclencheurs, vous devriez éviter les contraintes en cascade.

==> Voir ci-dessous la dernière modification, les choses bougent sur ce domaine

Et je ne pense pas que cela sera réparé un jour. Les contraintes de clé étrangère sont gérées par le stockage InnoDb et les déclencheurs sont gérés par le moteur MySQL SQL. Les deux sont séparés. Innodb est le seul stockage avec gestion des contraintes, peut-être ajoutera-t-il des déclencheurs directement dans le moteur de stockage un jour, peut-être pas.

Mais j'ai ma propre opinion sur l'élément que vous devriez choisir entre la mauvaise implémentation du déclencheur et le support très utile des contraintes de clés étrangères. Et une fois que vous vous serez habitué à la cohérence de la base de données, vous adorerez PostgreSQL.

12/2017-Mise à jour de cette modification à propos de MySQL :

comme l'indique @IstiaqueAhmed dans les commentaires, la donne a changé à ce sujet. Alors suivez le lien et vérifiez la situation réelle à jour (qui peut changer à nouveau à l'avenir).