2010-02-05 7 views
9

Der Hauptentwickler in einem Projekt, an dem ich beteiligt bin, sagt, es sei eine schlechte Praxis, sich auf Kaskaden zu verlassen, um verwandte Zeilen zu löschen.Ist es schlecht, sich auf die Kaskadierung von Fremdschlüsseln zu verlassen?

Ich sehe nicht, wie das schlecht ist, aber ich würde gerne Ihre Gedanken darüber wissen, wenn/warum es ist.

+0

Mögliches Duplikat von [Wann/Warum wird Kaskadierung in SQL Server verwendet?] (Http://stackoverflow.com/questions/59297/when-wy-to-use-cascading-in-sql-server). Außerdem stimme ich viel mehr mit den Antworten der anderen Frage überein, die ganz anders sind als die hier. –

Antwort

14

Ich werde das vorweg bringen, indem ich sage, dass ich Reihen selten Periode lösche. Im Allgemeinen die meisten Daten, die Sie behalten möchten. Sie markieren es einfach als gelöscht, damit es den Benutzern nicht angezeigt wird (dh für sie wird es gelöscht). Natürlich hängt es von den Daten ab und für einige Dinge (z. B. Einkaufswagen-Inhalt), die Datensätze tatsächlich zu löschen, wenn der Benutzer seinen Einkaufswagen leert, ist in Ordnung.

Ich kann nur annehmen, dass das Problem hier ist, dass Sie versehentlich Datensätze löschen können, die Sie nicht wirklich löschen möchten. Referenzielle Integrität sollte dies jedoch verhindern. Daher kann ich keinen anderen Grund dafür finden, als explizit zu sein.

+0

Ich muss hier mit celtus zustimmen, es sei denn, es gibt ein rechtliches oder echtes Kapazitätsproblem ... Speicher ist so billig und schnell, dass es heutzutage kaum einen wirklichen Grund gibt, hart zu löschen. +1 –

+4

Hier ist ein Grund - gelöschte Daten schleichen sich in Abfrageergebnisse zurück, weil jemand ein "AND DELETED = 0" vergessen hat. Wenn Sie dies tun, blenden Sie alle gelöschten Daten aus, die hinter einer reinen Live-Datenansicht stehen, oder Sie ** werden ** Probleme bekommen. –

+0

@Michael - hängt von Ihrer Architektur ab, zum Beispiel habe ich ein linq-Projekt und in den T4-Templates ist es trivial, einen '.Current()' Erweiterungsmethodenaufruf in den 'DataContext.GetTable ' Referenzen hinzuzufügen, die es erzeugt. Ich konnte sehen, dass dies in anderen Situationen ein Problem wäre, aber nicht * immer *. –

5

Ich verwende niemals kaskadierende Löschungen. Warum? Weil es zu leicht ist, einen Fehler zu machen. Viel sicherer erfordern Client-Anwendungen explizit löschen (und die Voraussetzungen für die Löschung erfüllen, wie das Löschen FK Aufzeichnungen bezeichnet.)

In der Tat, Deletionen per se kann durch Markieren Aufzeichnungen vermieden werden als gelöscht oder Umzug in Archiv-/Historientabellen.

Wenn Sie Datensätze als gelöscht markieren, hängt dies vom relativen Anteil der als gelöscht markierten Daten ab, da SELECT s nach 'isDeleted = false' filtern müssen. Ein Index wird nur verwendet, wenn weniger als 10% (ungefähr abhängig von der RDBMS) von Datensätzen werden als gelöscht markiert.

Welche dieser zwei Szenarien würden Sie bevorzugen:

1) Entwickler zu Ihnen kommt, sagt: „Hey, das nicht gelöscht wird funktionieren“. Ihr beide schaut hinein und stellt fest, dass er versehentlich versucht hat, ganze Tabelleninhalte zu löschen. Sie lachen beide und gehen zurück zu dem, was Sie getan haben.

2) Entwickler kommt zu Ihnen und fragt verlegen: "Haben wir Backups?"

+0

seit wann würden Sie triviale Daten löschen? Triviale Daten sind normalerweise statisch. Dieses Argument ist nicht stichhaltig. –

+0

Angenommen, ich unterstütze einen Auftrag aus dem System: Auftrag -> Einzelposten -> Kommentare. Wenn ich die Bestellung lösche (natürlich in der App zur Bestätigung), sind die Zeilen in den anderen 2 Tabellen jetzt nutzlos. Wenn Sie nicht eingerichtet sind, den übergeordneten Datensatz wiederherzustellen (in diesem Fall löschen Sie nicht ...), spielen die Kinder oft keine Rolle mehr. Sie können sie alle zusammen in einer Datenbank kaskadieren, indem Sie sie von Anfang an starten. Wie ich schon sagte, Sache der Anwendung und der Meinung, aber sie ** haben ** ihren Nutzen. –

+0

+1 für "Haben wir Backups?" – Neolisk

10

Ich würde sagen, dass Sie dem Prinzip der geringsten Überraschung folgen.

Überlappende Löschvorgänge sollten keinen unerwarteten Datenverlust verursachen. Wenn eine Löschung erfordert, dass verwandte Datensätze gelöscht werden, und der Benutzer wissen muss, dass diese Datensätze verschwinden, sollten keine überlappenden Löschvorgänge verwendet werden. Stattdessen sollte der Benutzer aufgefordert werden, die verknüpften Datensätze explizit zu löschen oder eine Benachrichtigung bereitzustellen.

Wenn sich die Tabelle andererseits auf eine andere Tabelle bezieht, die temporärer Natur ist oder Datensätze enthält, die nie mehr benötigt werden, nachdem die übergeordnete Entität nicht mehr vorhanden ist, sind möglicherweise überlappende Löschvorgänge OK.

Das sagte, ich bevorzuge meine Absichten explizit durch Löschen der zugehörigen Datensätze im Code, anstatt auf kaskadierende Löschungen. Tatsächlich habe ich niemals ein überlappendes Löschen verwendet, um verwandte Datensätze implizit zu löschen. Außerdem benutze ich oft eine weiche Löschung, wie von Cletus beschrieben.

+0

Das ist ein gutes Prinzip, es gibt genug natürlich vorkommende Überraschungen - keine Notwendigkeit, mehr von ihnen herzustellen. – Rawheiser

1

Ein weiterer wichtiger Grund, um kaskadierende Löschungen zu vermeiden, ist die Leistung. Sie scheinen eine gute Idee zu sein, bis Sie 10.000 Datensätze aus der Haupttabelle löschen müssen, die wiederum Millionen von Datensätzen in untergeordneten Tabellen enthalten.Angesichts der Größe dieses Löschvorgangs ist es wahrscheinlich, dass die gesamte Tabelle für Stunden oder Tage gesperrt wird. Warum würdest du das jemals riskieren? Für die Bequemlichkeit, zehn Minuten weniger Zeit zu verbringen, schreibt das Schreiben der zusätzlichen Löschanweisungen für einen Datensatz.

Weiter ist der Fehler, den Sie erhalten, wenn Sie versuchen, einen Datensatz zu löschen, der über einen unterordneten Datensatz verfügt, oft eine gute Sache. Es sagt Ihnen, dass Sie diesen Datensatz nicht löschen möchten, da Sie Daten benötigen, die Sie verlieren würden, wenn Sie dies tun würden. Cascade delete würde einfach weitergehen und die untergeordneten Datensätze löschen, was zum Verlust von Informationen über Aufträge führen würde, zum Beispiel, wenn Sie einen Kunden gelöscht haben, der Aufträge in der Vergangenheit hatte. Diese Art von Sache kann Ihre finanziellen Aufzeichnungen gründlich durcheinander bringen.

+0

Ich verstehe Ihr erstes Szenario nicht. Wie würde die alternative Arbeit, die die Perf Overhead vermeiden würde? Würden Sie einfach nicht löschen Untergeordnete Datensätze? Oder ist es die Tatsache, dass ein Löschen die Tabellen, die das Problem verursacht, irgendwie sperrt, und separate Löschungen vermeidet dies? –

+0

Sie würden die Löschvorgänge aus den untergeordneten Tabellen in Batches und dann das Haupt löschen. Ich würde niemandem erlauben Verwenden Sie Kaskadenlöschung in einer Datenbank vom Typ Produktionstyp Enterprise Es ist einfach zu wahrscheinlich, ein Produktionsproblem zu verursachen – HLGEM

+0

Im Falle von vielen Zeilen, die gelöscht werden müssen (in der referenzierten Tabelle), wäre die Leistung der kaskadierenden Löschungen besser, dein Code wird nicht schneller laufen als der in der DB, das andere Szenario ist mir fremd - du kannst "irrtümlich" nicht referenc löschen reihen. Wenn Sie eine FK als Kaskadierung deklariert haben, bedeutet dies, dass Sie nicht möchten, dass die referenzierenden Zeilen ohne die referenzierte Zeile existieren, was ein völlig akzeptabler Anwendungsfall ist. –

0

Ich wurde ebenfalls gesagt, dass kaskadierende Löschungen schlechte Praktiken waren ... und sie daher nie benutzt, bis ich auf einen Kunden stieß, der sie benutzte. Ich wusste wirklich nicht, warum ich sie nicht benutzen sollte, aber ich fand sie sehr praktisch, weil ich nicht alle FK-Datensätze löschen musste.

Also entschied ich zu erforschen, warum sie so "schlecht" waren und von dem, was ich bis jetzt gefunden habe, scheint nichts problematisch zu sein. In der Tat ist das einzige gute Argument, das ich bisher gesehen habe, HLGLEM, was oben über die Leistung gesagt wurde. Aber da ich diese Anzahl von Datensätzen normalerweise nicht lösche, denke ich, dass in den meisten Fällen die Verwendung dieser Datensätze in Ordnung sein sollte. Ich würde gerne von anderen Argumenten hören, die andere gegen ihre Verwendung haben könnten, um sicherzustellen, dass ich alle Optionen in Betracht gezogen habe.

+1

Das Problem mit cascade on delete ist, wenn Sie versehentlich einen Wert aus der referenzierten Tabelle löschen, werden alle Zeilen gelöscht, die diesen Wert verwenden (nicht nur der Wert in diesen Zeilen, sondern die ganze Zeile). Scheint wirklich dumm, aber ich habe es heute auf die harte Art gelernt. – Holonaut

+0

@Holonaut Ich sehe, was du sagst, das wäre ein Problem. Aber ich sehe das gleiche Problem, wenn Sie versehentlich einen Datensatz programmatisch gelöscht haben, so wie ich es normalerweise mit einem Klick auf den Knopf mache. –