Unter welchen Umständen sollte beim Einrichten von Fremdschlüsseln in SQL Server diese beim Löschen oder Aktualisieren kaskadiert werden, und was ist der Grund dafür?
Dies gilt wahrscheinlich auch für andere Datenbanken.
Ich suche vor allem nach konkreten Beispielen für jedes Szenario, vorzugsweise von jemandem, der sie erfolgreich eingesetzt hat.
sql-server
database-design
foreign-keys
rdbms
cascade
Joel Coehoorn
quelle
quelle
sql-server
Tag entfernen .Antworten:
Zusammenfassung dessen, was ich bisher gesehen habe:
Kaskade löschen
Kaskaden-Update
Wann wird Cascading verwendet?
quelle
Fremdschlüssel sind der beste Weg, um die referenzielle Integrität einer Datenbank sicherzustellen. Das Vermeiden von Kaskaden aufgrund von Magie ist wie das Schreiben von allem in Assembly, weil Sie der Magie hinter Compilern nicht vertrauen.
Was schlecht ist, ist die falsche Verwendung von Fremdschlüsseln, wie sie beispielsweise rückwärts erstellt werden.
Das Beispiel von Juan Manuel ist das kanonische Beispiel. Wenn Sie Code verwenden, besteht eine viel größere Wahrscheinlichkeit, dass falsche DocumentItems in der Datenbank verbleiben, die Sie beißen.
Kaskadierende Aktualisierungen sind beispielsweise nützlich, wenn Sie Verweise auf die Daten haben, die sich ändern können. Angenommen, ein Primärschlüssel einer Benutzertabelle ist die Kombination aus Name und Nachname. Dann möchten Sie, dass Änderungen in dieser Kombination überall dort weitergegeben werden, wo sie referenziert werden.
@Aidan, Diese Klarheit, auf die Sie sich beziehen, ist mit hohen Kosten verbunden. Die Wahrscheinlichkeit, dass falsche Daten in Ihrer Datenbank verbleiben, ist nicht gering . Für mich ist es normalerweise nur mangelnde Vertrautheit mit der DB und Unfähigkeit, herauszufinden, welche FKs vorhanden sind, bevor ich mit der DB zusammenarbeite, die diese Angst fördern. Entweder das oder ständiger Missbrauch der Kaskade, wenn die Entitäten konzeptionell nicht miteinander verbunden waren oder wenn Sie die Geschichte bewahren müssen.
quelle
Ich verwende niemals kaskadierende Löschvorgänge.
Wenn ich möchte, dass etwas aus der Datenbank entfernt wird, möchte ich der Datenbank explizit mitteilen, was ich herausnehmen möchte.
Natürlich sind sie eine Funktion, die in der Datenbank verfügbar ist, und es kann vorkommen, dass sie in Ordnung sind. Wenn Sie beispielsweise eine 'order'-Tabelle und eine' orderItem'-Tabelle haben, möchten Sie die Elemente möglicherweise löschen, wenn Sie eine löschen Auftrag.
Ich mag die Klarheit, die ich bekomme, wenn ich es in Code (oder einer gespeicherten Prozedur) mache, anstatt dass 'Magie' passiert.
Aus dem gleichen Grund bin ich auch kein Fan von Triggern.
Wenn Sie eine 'Bestellung' löschen, erhalten Sie den Bericht '1 Zeile betroffen' zurück, selbst wenn durch das kaskadierte Löschen 50 'orderItem' entfernt wurden.
quelle
Ich arbeite viel mit kaskadierenden Löschvorgängen.
Es fühlt sich gut an zu wissen, wer gegen die Datenbank arbeitet, darf niemals unerwünschte Daten hinterlassen. Wenn Abhängigkeiten zunehmen, ändere ich einfach die Einschränkungen im Diagramm in Management Studio und muss weder sp noch Datenzugriffe anpassen.
Das heißt, ich habe 1 Problem mit kaskadierenden Löschvorgängen und das sind Zirkelverweise. Dies führt häufig zu Teilen der Datenbank, die keine kaskadierenden Löschvorgänge aufweisen.
quelle
Ich mache viel Datenbankarbeit und finde Kaskadenlöschungen selten nützlich. Das einzige Mal, dass ich sie effektiv verwendet habe, befindet sich in einer Berichtsdatenbank, die durch einen nächtlichen Job aktualisiert wird. Ich stelle sicher, dass alle geänderten Daten korrekt importiert werden, indem ich alle Datensätze der obersten Ebene lösche, die sich seit dem letzten Import geändert haben, und dann die geänderten Datensätze und alles, was damit zusammenhängt, erneut importiere. Es erspart mir das Schreiben vieler komplizierter Löschvorgänge, die von unten nach oben in meiner Datenbank angezeigt werden.
Ich halte Kaskadenlöschungen nicht für so schlimm wie Trigger, da sie nur Daten löschen. Trigger können alle möglichen bösen Dinge enthalten.
Im Allgemeinen vermeide ich echte Löschvorgänge insgesamt und verwende stattdessen logische Löschvorgänge (dh eine Bitspalte namens isDeleted, die auf true gesetzt wird).
quelle
Ein Beispiel ist, wenn Sie Abhängigkeiten zwischen Entitäten haben ... dh: Dokument -> DocumentItems (wenn Sie Document löschen, haben DocumentItems keinen Grund zu existieren)
quelle
Verwenden Sie Kaskadenlöschung, wenn der Datensatz mit der FK entfernt werden soll, wenn der verweisende PK-Datensatz entfernt wurde. Mit anderen Worten, wenn der Datensatz ohne den referenzierenden Datensatz bedeutungslos ist.
Ich finde das Löschen von Kaskaden nützlich, um sicherzustellen, dass tote Referenzen standardmäßig entfernt werden, anstatt Null-Ausnahmen zu verursachen.
quelle
EIN Kaskade löschen:
Wenn Zeilen in der untergeordneten Tabelle gelöscht werden sollen Wenn die entsprechende Zeile in der übergeordneten Tabelle gelöscht wird .
Wenn das Löschen in der Kaskade nicht verwendet wird, wird ein Fehler für die referenzielle Integrität ausgelöst .
ON Update Cascade:
Wenn Sie Änderung der Primärschlüssel in aktualisiert werden Fremdschlüssel
quelle
Ich habe von Datenbankadministratoren und / oder "Unternehmensrichtlinien" gehört, die die Verwendung von "On Delete Cascade" (und anderen) nur aufgrund schlechter Erfahrungen in der Vergangenheit verbieten. In einem Fall schrieb ein Mann drei Auslöser, die sich gegenseitig anriefen. Drei Tage, um sich zu erholen, führten zu einem völligen Verbot von Auslösern, alles aufgrund der Handlungen eines Idjits.
Natürlich werden manchmal Trigger anstelle von "On Delete Cascade" benötigt, beispielsweise wenn einige untergeordnete Daten beibehalten werden müssen. In anderen Fällen ist es jedoch durchaus gültig, die Kaskadenmethode On Delete zu verwenden. Ein wesentlicher Vorteil der "On Delete-Kaskade" besteht darin, dass ALLE Kinder erfasst werden. Eine benutzerdefinierte geschriebene Trigger- / Speicherprozedur funktioniert möglicherweise nicht, wenn sie nicht korrekt codiert ist.
Ich glaube, der Entwickler sollte die Entscheidung treffen dürfen, basierend auf der Entwicklung und den Angaben in der Spezifikation. Ein Teppichverbot aufgrund einer schlechten Erfahrung sollte nicht das Kriterium sein. Der Denkprozess "Niemals benutzen" ist bestenfalls drakonisch. Jedes Mal muss eine Entscheidung getroffen und Änderungen vorgenommen werden, wenn sich das Geschäftsmodell ändert.
Geht es nicht um Entwicklung?
quelle
Ein Grund für das Löschen einer Kaskade (anstatt dies im Code zu tun) ist die Verbesserung der Leistung.
Fall 1: Mit einer Kaskade löschen
Fall 2: Ohne Kaskade löschen
Zweitens funktioniert der Code in Fall 1 weiter, wenn Sie eine zusätzliche untergeordnete Tabelle mit einer Kaskadenlöschung hinzufügen.
Ich würde nur eine Kaskade einsetzen, in der die Semantik der Beziehung "Teil" ist. Andernfalls löscht ein Idiot die Hälfte Ihrer Datenbank, wenn Sie Folgendes tun:
quelle
Ich versuche, Löschungen oder Aktualisierungen zu vermeiden, die ich in SQL Server nicht explizit angefordert habe.
Entweder durch Kaskadierung oder durch die Verwendung von Triggern. Sie neigen dazu, Sie irgendwann in den Arsch zu beißen, entweder wenn Sie versuchen, einen Fehler aufzuspüren, oder wenn Sie Leistungsprobleme diagnostizieren.
Wo ich sie verwenden würde, ist die Gewährleistung der Konsistenz für nicht sehr viel Aufwand. Um den gleichen Effekt zu erzielen, müssten Sie gespeicherte Prozeduren verwenden.
quelle
Ich finde, wie alle anderen hier, dass Kaskadenlöschungen wirklich nur am Rande hilfreich sind (es ist wirklich nicht so viel Arbeit, referenzierte Daten in anderen Tabellen zu löschen - wenn es viele Tabellen gibt, automatisieren Sie dies einfach mit einem Skript), aber wirklich ärgerlich Wenn jemand versehentlich eine Kaskade löscht, werden einige wichtige Daten gelöscht, die schwer wiederherzustellen sind.
Der einzige Fall, den ich verwenden würde, ist, wenn die Daten in der Tabellentabelle stark kontrolliert werden (z. B. eingeschränkte Berechtigungen) und nur durch einen kontrollierten Prozess (wie ein Software-Update) aktualisiert oder gelöscht werden, der überprüft wurde.
quelle
Ein Löschen oder Aktualisieren von S, bei dem ein in einigen Tupeln von R gefundener Fremdschlüsselwert entfernt wird, kann auf drei Arten behandelt werden:
Die Ausbreitung wird als Kaskadierung bezeichnet.
Es gibt zwei Fälle:
‣ Wenn ein Tupel in S gelöscht wurde, löschen Sie die darauf bezogenen R-Tupel.
‣ Wenn ein Tupel in S aktualisiert wurde, aktualisieren Sie den Wert in den R-Tupeln, die darauf verweisen.
quelle
Wenn Sie an einem System mit vielen verschiedenen Modulen in verschiedenen Versionen arbeiten, kann es sehr hilfreich sein, wenn die kaskadengelöschten Elemente Teil des PK-Inhabers sind / diesem gehören. Andernfalls würden alle Module sofortige Patches benötigen, um ihre abhängigen Elemente zu bereinigen, bevor der PK-Besitzer gelöscht wird, oder die Fremdschlüsselbeziehung würde vollständig weggelassen, wodurch möglicherweise Tonnen von Müll im System verbleiben, wenn die Bereinigung nicht korrekt durchgeführt wird.
Ich habe gerade das Kaskadenlöschen für eine neue Schnittpunkttabelle zwischen zwei bereits vorhandenen Tabellen eingeführt (die Schnittmenge, die nur gelöscht werden soll), nachdem das Löschen von Kaskaden für einige Zeit nicht mehr empfohlen wurde. Es ist auch nicht schlecht, wenn Daten verloren gehen.
Bei enumartigen Listentabellen ist dies jedoch eine schlechte Sache: Jemand löscht Eintrag 13 - gelb aus der Tabelle "Farben", und alle gelben Elemente in der Datenbank werden gelöscht. Außerdem werden diese manchmal auf eine Weise aktualisiert, bei der alle gelöscht werden, was dazu führt, dass die referenzielle Integrität vollständig weggelassen wird. Natürlich ist es falsch, aber wie werden Sie eine komplexe Software ändern, die seit vielen Jahren ausgeführt wird, wobei die Einführung einer echten referenziellen Integrität das Risiko unerwarteter Nebenwirkungen birgt?
Ein weiteres Problem besteht darin, dass die ursprünglichen Fremdschlüsselwerte auch nach dem Löschen des Primärschlüssels beibehalten werden sollen. Man kann eine Tombstone-Spalte und eine ON DELETE SET NULL-Option für den ursprünglichen FK erstellen, dies erfordert jedoch wiederum Trigger oder spezifischen Code, um den redundanten Schlüsselwert (außer nach dem Löschen der PK) beizubehalten.
quelle
Kaskadenlöschungen sind äußerst nützlich, wenn logische Entitäten vom Typ Super und Subtyp in einer physischen Datenbank implementiert werden.
Wenn getrennte Supertyp- und Untertyp-Tabellen verwendet werden, um Supertypen / Untertypen physisch zu implementieren (im Gegensatz zum Aufrollen aller Untertypattribute in eine einzige physische Supertyp-Tabelle), gibt es eine Eins-zu-Tabelle -eine Beziehung zwischen diesen Tabellen und dem Problem wird dann, wie die Primärschlüssel zu 100% zwischen diesen Tabellen synchron gehalten werden.
Kaskadenlöschungen können ein sehr nützliches Werkzeug sein, um:
1) Stellen Sie sicher, dass durch das Löschen eines Super-Typ-Datensatzes auch der entsprechende einzelne Sub-Typ-Datensatz gelöscht wird.
2) Stellen Sie sicher, dass beim Löschen eines Untertypdatensatzes auch der Supertypdatensatz gelöscht wird. Dies wird erreicht, indem ein "statt" -Löschauslöser in der Untertypentabelle implementiert wird, der den entsprechenden Supertypdatensatz löscht, der wiederum den Untertypdatensatz durch Kaskade löscht.
Durch die Verwendung von Kaskadenlöschvorgängen auf diese Weise wird sichergestellt, dass niemals verwaiste Supertyp- oder Untertypdatensätze vorhanden sind, unabhängig davon, ob Sie zuerst den Supertypdatensatz oder den Untertypdatensatz zuerst löschen.
quelle