Quand / pourquoi utiliser la mise en cascade dans SQL Server?

149

Lors de la configuration de clés étrangères dans SQL Server, dans quelles circonstances devez-vous les mettre en cascade lors de la suppression ou de la mise à jour, et quel en est le raisonnement?

Cela s'applique probablement aussi à d'autres bases de données.

Je recherche surtout des exemples concrets de chaque scénario, de préférence de quelqu'un qui les a utilisés avec succès.

Joël Coehoorn
la source
4
Cette question ne semble pas strictement liée à SQL Server et ressemble plus à une question théorique générale. Ce serait plus utile pour la communauté si vous supprimez la sql-serverbalise.
clapas du
4
@clapas Honnêtement, si je devais le demander aujourd'hui, ce serait hors sujet. Sinon pour les vues / votes élevés indiquant qu'il a de la valeur pour la communauté, je le supprimerais simplement.
Joel Coehoorn
6
@JoelCoehoorn - De toute évidence, ces types de questions ont une valeur. Cette valeur ne se dissipe pas avec le temps. La question dans mon esprit est de savoir quelle valeur perdons-nous en refusant de telles questions aujourd'hui?
P.Brian.Mackey
2
@ P.Brian.Mackey Ici, ici! Certaines des meilleures questions / réponses que j'ai vues sont celles qui ont été votées à la baisse ou qui ont été qualifiées de hors sujet ... mais vous pouvez dire par le nombre ÉNORME de votes à la hausse que beaucoup ont eu exactement la même question!
Anthony Griggs
Les actions en cascade prennent des verrous sérialisables.
Mitch Wheat

Réponses:

127

Résumé de ce que j'ai vu jusqu'à présent:

  • Certaines personnes n'aiment pas du tout la cascade.

Suppression en cascade

  • La suppression en cascade peut avoir un sens lorsque la sémantique de la relation peut impliquer une description exclusive «fait partie de ». Par exemple, un enregistrement OrderLine fait partie de sa commande parent et OrderLines ne sera jamais partagé entre plusieurs commandes. Si l'Ordre devait disparaître, la OrderLine le devrait également, et une ligne sans Commande serait un problème.
  • L'exemple canonique de Cascade Delete est SomeObject et SomeObjectItems, où il n'a aucun sens pour un enregistrement d'éléments d'exister sans un enregistrement principal correspondant.
  • Vous ne devez pas utiliser la suppression en cascade si vous préservez l'historique ou si vous utilisez une «suppression logicielle / logicielle» dans laquelle vous ne définissez qu'une colonne de bits supprimée sur 1 / vrai.

Mise à jour en cascade

  • La mise à jour en cascade peut avoir un sens lorsque vous utilisez une clé réelle plutôt qu'une clé de substitution (colonne d'identité / auto-incrémentation) dans les tables.
  • L'exemple canonique de Cascade Update est lorsque vous avez une clé étrangère mutable, comme un nom d'utilisateur qui peut être modifié.
  • Vous ne devez pas utiliser la mise à jour en cascade avec des clés qui sont des colonnes d'identité / auto-incrémentation.
  • La mise à jour en cascade est mieux utilisée en conjonction avec une contrainte unique.

Quand utiliser la cascade

  • Vous souhaiterez peut-être obtenir une confirmation supplémentaire de la part de l'utilisateur avant d'autoriser la mise en cascade d'une opération, mais cela dépend de votre application.
  • La mise en cascade peut vous causer des problèmes si vous avez mal configuré vos clés étrangères. Mais vous devriez être d'accord si vous faites cela correctement.
  • Il n'est pas sage d'utiliser la cascade avant de bien la comprendre. Cependant, c'est une fonctionnalité utile et vaut donc la peine de prendre le temps de la comprendre.
Joël Coehoorn
la source
3
Notez que les mises à jour en cascade sont également souvent utilisées là où les "soi-disant" clés naturelles ne semblent pas être ces véritables clés uniques efficaces. En fait, je suis convaincu que les mises à jour en cascade ne sont nécessaires qu'avec des modèles de base de données mal normalisés, et elles sont une porte ouverte vers des tables en désordre et du code en désordre.
Philippe Grondier
1
Il vous manque un point important, la cascade peut créer d'énormes problèmes de performances s'il existe de nombreux enregistrements enfants.
HLGEM
13
@HLGEM - Je ne vois pas la pertinence. Si des opérations en cascade provoquent un ralentissement, le processus manuel équivalent entraînerait le même ralentissement ou ne serait pas correctement protégé au cas où la transaction doit être annulée.
Joel Coehoorn
3
Pourquoi est-ce important qu'il y ait une mise à jour en cascade sur une colonne IDENTITY ou auto-incrémentée? Je peux voir pourquoi il ne serait pas nécessaire parce que vous ne devriez pas avoir besoin de changer ces valeurs (arbitraires), mais si l' un d'entre eux a fait le changement, au moins est intacte l'intégrité référentielle.
Kenny Evitt
3
10 balles? Eh bien maintenant, nous savons que Joel ne tire pas de revolver.
Neil N
69

Les clés étrangères sont le meilleur moyen de garantir l'intégrité référentielle d'une base de données. Éviter les cascades parce que c'est magique, c'est comme tout écrire en assemblage parce que vous ne faites pas confiance à la magie des compilateurs.

Ce qui est mauvais, c'est la mauvaise utilisation des clés étrangères, comme les créer à l'envers, par exemple.

L'exemple de Juan Manuel est l'exemple canonique, si vous utilisez du code, il y a beaucoup plus de chances de laisser de faux DocumentItems dans la base de données qui viendront vous mordre.

Les mises à jour en cascade sont utiles, par exemple, lorsque vous avez des références aux données par quelque chose qui peut changer, disons qu'une clé primaire d'une table users est le nom, la combinaison de nom. Ensuite, vous voulez que les modifications de cette combinaison se propagent là où elles sont référencées.

@Aidan, Cette clarté dont vous parlez a un coût élevé, le risque de laisser des données fausses dans votre base de données, ce qui n'est pas petit . Pour moi, c'est généralement juste un manque de familiarité avec la DB et l'incapacité de trouver quels FK sont en place avant de travailler avec la DB qui alimentent cette peur. Soit cela, soit une utilisation abusive constante de la cascade, en l'utilisant là où les entités n'étaient pas liées conceptuellement, ou là où vous devez préserver l'histoire.

Vinko Vrsalovic
la source
7
L'utilisation de ce type de clé primaire «naturelle» est une très mauvaise idée en premier lieu.
Nick Johnson
1
L'idée était de montrer un exemple sur les mises à jour en cascade, je conviens que ce n'est pas le meilleur exemple cependant. Les emplacements des fichiers peuvent être un meilleur exemple.
Vinko Vrsalovic
4
RE: Commentaire adressé à Aidan. Non, laisser CASCADE sur un FK n'augmente pas le risque de laisser des données parasites. Cela diminue le risque que plus de données soient affectées par une commande que prévu et augmente le code. Le fait de ne pas tenir compte des FK laisse entièrement une chance à des données parasites.
Shannon Severance
5
Ayant vu au moins deux fois dans ma carrière les conséquences menaçantes pour les entreprises d'une suppression en cascade mal comprise, je suis très peu enclin à les utiliser moi-même dans tous, sauf dans les cas les plus évidents. Dans les deux cas, les données avaient été supprimées à la suite d'une cascade qui aurait vraiment dû être conservée mais qui ne l'était pas - et le fait qu'il manquait n'a pas été détecté jusqu'à ce que le cycle de sauvegarde normal ait perdu la possibilité d'une restauration facile. Vinko est correct d'un point de vue purement logique, mais dans le monde réel, l'utilisation de cascades expose plus que je ne le souhaiterais à la faillibilité humaine et aux conséquences imprévues.
Cruachan
7
@Cruachan: La règle, à mon avis, est simple. Si les données ne sont pas aussi étroitement liées qu'elles ne sont pas utiles sans les données parentes, cela ne justifie pas une relation en cascade. C'est ce que j'ai essayé d'aborder dans la dernière phrase de ma réponse.
Vinko Vrsalovic
17

Je n'utilise jamais de suppressions en cascade.

Si je veux que quelque chose soit supprimé de la base de données, je veux dire explicitement à la base de données ce que je veux retirer.

Bien sûr, il s'agit d'une fonction disponible dans la base de données et il peut y avoir des moments où il est acceptable de les utiliser, par exemple si vous avez une table 'order' et une table 'orderItem', vous voudrez peut-être effacer les éléments lorsque vous supprimez un ordre.

J'aime la clarté que j'obtiens en le faisant dans le code (ou la procédure stockée) plutôt que dans la «magie».

Pour la même raison, je ne suis pas non plus fan des déclencheurs.

Quelque chose à noter est que si vous supprimez une 'commande', vous obtiendrez un rapport '1 ligne affectée' même si la suppression en cascade a supprimé 50 'orderItem'.

Loofer
la source
34
Pourquoi ne pas vous débarrasser également des clés primaires? Vous obtiendrez la clarté d'assurer des valeurs uniques dans votre code.
MusiGenesis
4
@MusiGenesis, Aidan ne préconisait pas la suppression du FK. Le FK protège toujours les données, mais sans CASCADE ON .... la magie inattendue ne se produit pas.
Shannon Severance
7
@Vinko: Delete et update ont une sémantique par défaut bien définie. Changer le comportement via une cascade ou un déclencheur pour faire plus de travail laisse une chance d'avoir fait plus que prévu. Non, je ne travaille pas sans tests et oui mes bases de données sont documentées. Mais est-ce que je me souviens de chaque élément de la documentation en écrivant du code? Si je veux une sémantique de niveau supérieur, comme supprimer le parent et les enfants, j'écrirai et utiliserai un SP pour le faire.
Shannon Severance
3
@Vinko. le problème de la magie n'est pas avec les développeurs compétents ou les DBA, c'est avec Joe interen 5 ans plus tard qui s'est vu confier une tâche de maintenance `` simple '' lorsque le DBA est en vacances et qui bousille ensuite les données de l'entreprise sans que personne ne s'en rende compte. Les cascades ont leur place, mais il est important de considérer l'ensemble des circonstances, y compris les facteurs humains, avant de les déployer.
Cruachan
5
@Vinko: Pourquoi les SP 'Gasp'? Les SP sont incontestablement la voie à suivre là où la base de données est un actif critique de l'entreprise. Il y a un argument fort dans le genre de circonstances dont on parlait pour restreindre tous les accès aux données aux SP, ou du moins à tous sauf à Select. Voir ma réponse sous stackoverflow.com/questions/1171769/…
Cruachan
13

Je travaille beaucoup avec des suppressions en cascade.

Il est bon de savoir que quiconque travaille sur la base de données ne laissera jamais de données indésirables. Si les dépendances augmentent, je change simplement les contraintes dans le diagramme dans Management Studio et je n'ai pas à modifier sp ou dataacces.

Cela dit, j'ai 1 problème avec les suppressions en cascade et les références circulaires. Cela conduit souvent à des parties de la base de données qui n'ont pas de suppressions en cascade.

Mathias F
la source
1
Je sais que c'est très ancien, mais +1 pour avoir mentionné le problème de référence circulaire avec CASCADE DELETE.
Code Maverick
2
Pardonnez une question noob: que se passe-t-il réellement si vous obtenez une référence circulaire?
Tim Lovell-Smith le
10

Je fais beaucoup de travail sur les bases de données et je trouve rarement les suppressions en cascade utiles. La seule fois où je les ai utilisés efficacement, c'est dans une base de données de rapports qui est mise à jour par un travail de nuit. Je m'assure que toutes les données modifiées sont importées correctement en supprimant tous les enregistrements de niveau supérieur qui ont changé depuis la dernière importation, puis réimportez les enregistrements modifiés et tout ce qui s'y rapporte. Cela m'évite d'avoir à écrire beaucoup de suppressions compliquées qui vont du bas vers le haut de ma base de données.

Je ne considère pas que les suppressions en cascade soient aussi mauvaises que les déclencheurs car elles ne suppriment que des données, les déclencheurs peuvent contenir toutes sortes de choses désagréables.

En général, j'évite complètement les suppressions réelles et j'utilise des suppressions logiques (c'est-à-dire avoir une colonne de bits appelée isDeleted qui est mise à true) à la place.

Martynnw
la source
2
Vous m'avez curieux d'en savoir plus. Pourquoi préférez-vous fortement les suppressions logiques? Les données avec lesquelles vous travaillez ont-elles quelque chose à voir avec cela?
Tim Lovell-Smith le
9

Un exemple est lorsque vous avez des dépendances entre des entités ... c'est-à-dire: Document -> DocumentItems (lorsque vous supprimez Document, DocumentItems n'a pas de raison d'exister)

Juan
la source
5

Utilisez la suppression en cascade là où vous souhaitez que l'enregistrement avec le FK soit supprimé si son enregistrement PK de référence a été supprimé. En d'autres termes, lorsque l'enregistrement n'a pas de sens sans l'enregistrement de référence.

Je trouve la suppression en cascade utile pour garantir que les références mortes sont supprimées par défaut plutôt que de provoquer des exceptions nulles.

Modèle de test
la source
5

ON Supprimer la cascade:

Lorsque vous souhaitez que les lignes de la table enfant soient supprimées Si la ligne correspondante est supprimée de la table parent.

Si la suppression en cascade n'est pas utilisée, une erreur sera générée pour l' intégrité référentielle .

ON Update Cascade:

Lorsque vous souhaitez que la modification de la clé primaire soit mise à jour dans la clé étrangère

Durai Amuthan.H
la source
5

J'ai entendu parler des administrateurs de base de données et / ou de la «politique de l'entreprise» qui interdisent d'utiliser «On Delete Cascade» (et d'autres) uniquement en raison de mauvaises expériences dans le passé. Dans un cas, un gars a écrit trois déclencheurs qui ont fini par s'appeler. Trois jours pour récupérer ont abouti à une interdiction totale des déclencheurs, tout cela à cause des actions d'un idjit.

Bien sûr, parfois, des déclencheurs sont nécessaires au lieu de "En cas de suppression en cascade", comme lorsque certaines données enfants doivent être préservées. Mais dans d'autres cas, il est parfaitement valable d'utiliser la méthode en cascade On Delete. Un avantage clé de "On Delete cascade" est qu'il capture TOUS les enfants; une procédure de déclenchement / stockage écrite personnalisée peut ne pas l'être si elle n'est pas codée correctement.

Je pense que le développeur devrait être autorisé à prendre la décision en fonction de ce qu'est le développement et de ce que dit la spécification. Une interdiction de tapis basée sur une mauvaise expérience ne devrait pas être le critère; le processus de pensée «Ne jamais utiliser» est au mieux draconien. Un appel au jugement doit être fait à chaque fois, et des changements sont apportés à mesure que le modèle commercial évolue.

N'est-ce pas là tout le sens du développement?

BrianBurkill
la source
Je ne pensais pas que cela supprimerait tout ... vous voulez dire que la fonctionnalité fait réellement ce qu'elle dit? ...
Joel Coehoorn
3

Une des raisons de mettre une suppression en cascade (plutôt que de le faire dans le code) est d'améliorer les performances.

Cas 1: avec une suppression en cascade

 DELETE FROM table WHERE SomeDate < 7 years ago;

Cas 2: sans suppression en cascade

 FOR EACH R IN (SELECT FROM table WHERE SomeDate < 7 years ago) LOOP
   DELETE FROM ChildTable WHERE tableId = R.tableId;
   DELETE FROM table WHERE tableId = R.tableid;
   /* More child tables here */
 NEXT

Deuxièmement, lorsque vous ajoutez une table enfant supplémentaire avec une suppression en cascade, le code du cas 1 continue de fonctionner.

Je mettrais seulement dans une cascade où la sémantique de la relation fait "partie de". Sinon, un idiot supprimera la moitié de votre base de données lorsque vous faites:

DELETE FROM CURRENCY WHERE CurrencyCode = 'USD'
WW.
la source
5
Ne sachant pas quelle base de données vous utilisez, je suggérerais que votre suppression manuelle soit pire que la suppression en cascade car elle n'est pas définie en fonction. Dans la plupart des bases de données, vous pouvez supprimer en fonction d'une jointure à une autre table et ainsi effectuer une suppression basée sur un ensemble, beaucoup plus rapide que la lecture en boucle des enregistrements.
HLGEM
2

J'essaie d'éviter les suppressions ou les mises à jour que je n'ai pas explicitement demandées dans le serveur SQL.

Soit en cascade, soit en utilisant des déclencheurs. Ils ont tendance à vous mordre dans le cul un certain temps, que ce soit lorsqu'ils essaient de localiser un bug ou lorsqu'ils diagnostiquent des problèmes de performance.

Là où je les utiliserais, c'est pour garantir la cohérence pour peu d'efforts. Pour obtenir le même effet, vous devrez utiliser des procédures stockées.

pauliephonique
la source
2

Comme tout le monde ici, je trouve que les suppressions en cascade ne sont vraiment utiles que marginalement (ce n'est vraiment pas beaucoup de travail de supprimer des données référencées dans d'autres tables - s'il y a beaucoup de tables, vous automatisez simplement cela avec un script) mais vraiment ennuyeux lorsqu'une personne en cascade supprime accidentellement des données importantes difficiles à restaurer.

Le seul cas où j'utiliserais est si les données de la table de table sont hautement contrôlées (par exemple, des autorisations limitées) et uniquement mises à jour ou supprimées via un processus contrôlé (comme une mise à jour logicielle) qui a été vérifiée.

Jen A
la source
1

Une suppression ou une mise à jour de S qui supprime une valeur de clé étrangère trouvée dans certains tuples de R peut être gérée de trois manières:

  1. Rejet
  2. Propagation
  3. annulation.

La propagation est appelée cascade.

Il y a deux cas:

‣ Si un tuple de S a été supprimé, supprimez les R tuples qui y faisaient référence.

‣ Si un tuple dans S a été mis à jour, mettez à jour la valeur dans les tuples R qui y font référence.

Mayank Chopra
la source
0

Si vous travaillez sur un système avec de nombreux modules différents dans différentes versions, cela peut être très utile si les éléments supprimés en cascade font partie de / appartiennent au détenteur de PK. Sinon, tous les modules nécessiteraient des correctifs immédiats pour nettoyer leurs éléments dépendants avant de supprimer le propriétaire PK, ou la relation de clé étrangère serait complètement omise, laissant éventuellement des tonnes de déchets dans le système si le nettoyage n'est pas effectué correctement.

Je viens d'introduire la suppression en cascade pour une nouvelle table d'intersection entre deux tables déjà existantes (l'intersection à supprimer uniquement), après que la suppression en cascade ait été découragée depuis un certain temps. Ce n'est pas trop mal non plus si les données sont perdues.

C'est, cependant, une mauvaise chose sur les tables de liste de type énumération: quelqu'un supprime l'entrée 13 - jaune de la table "couleurs", et tous les éléments jaunes de la base de données sont supprimés. En outre, ceux-ci sont parfois mis à jour d'une manière delete-all-insert-all, conduisant à une intégrité référentielle totalement omise. Bien sûr, c'est faux, mais comment allez-vous changer un logiciel complexe qui fonctionne depuis de nombreuses années, l'introduction d'une véritable intégrité référentielle risquant de provoquer des effets secondaires inattendus?

Un autre problème est lorsque les valeurs de clé étrangère d'origine doivent être conservées même après la suppression de la clé primaire. On peut créer une colonne tombstone et une option ON DELETE SET NULL pour le FK d'origine, mais cela nécessite à nouveau des déclencheurs ou un code spécifique pour maintenir la valeur de clé redondante (sauf après la suppression de PK).

Erik Hart
la source
0

Les suppressions en cascade sont extrêmement utiles lors de l'implémentation d'entités de super-types et de sous-types logiques dans une base de données physique.

Lorsque des tables de super-types et de sous-types séparées sont utilisées pour implémenter physiquement des super-types / sous-types (par opposition à regrouper tous les attributs de sous-type dans une seule table de super-type physique), il existe un -une relation entre ces tables et le problème devient alors comment garder les clés primaires 100% synchronisées entre ces tables.

Les suppressions en cascade peuvent être un outil très utile pour:

1) Assurez-vous que la suppression d'un enregistrement de super-type supprime également l'enregistrement de sous-type unique correspondant.

2) Assurez-vous que toute suppression d'un enregistrement de sous-type supprime également l'enregistrement de super-type. Ceci est réalisé en implémentant un déclencheur de suppression "au lieu de" sur la table de sous-type qui va et supprime l'enregistrement de super-type correspondant, qui, à son tour, supprime en cascade l'enregistrement de sous-type.

L'utilisation de suppressions en cascade de cette manière garantit qu'aucun enregistrement de super-type ou de sous-type orphelin n'existe jamais, que vous supprimiez d'abord l'enregistrement de super-type ou l'enregistrement de sous-type en premier.

Mark Allen
la source
Bon exemple. Dans JPA, il s'agit de la table jointe InheritanceStrategy. Pour 1): Normalement, vous utilisez un framework de couches de persistance (EclipseLink, Hibernate, ...), qui implémente la séquence supprimée pour une entité jointe pour supprimer d'abord la partie jointe, puis la super partie. Mais si vous avez un logiciel plus basique en place, comme une tâche d'importation ou d'archivage, il est pratique de pouvoir simplement supprimer l'entité en émettant une suppression sur la super partie. Concernant 2): d'accord, mais dans ce cas, le client doit déjà être conscient qu'il travaille sur une partie jointe / sous de l'entité.
leo