Ich möchte eine Funktion zum "Wiederherstellen" in einer Webanwendung implementieren, damit ein Benutzer seine Meinung ändern und einen gelöschten Datensatz wiederherstellen kann. Überlegungen zur Umsetzung? Einige Optionen, die ich in Betracht gezogen habe, sind das Löschen des betreffenden Datensatzes und das Speichern der Änderungen in einer separaten Prüftabelle oder das Nicht-Löschen des Datensatzes und die Verwendung einer booleschen Spalte "gelöscht", um ihn als gelöscht zu markieren. Die letztere Lösung würde zusätzliche Anwendungslogik erfordern, um die "gelöschten" Datensätze unter normalen Umständen zu ignorieren, würde es jedoch wesentlich einfacher machen, die Datensätze auf der Anwendungsseite wiederherzustellen.
database-design
delete
audit
Abie
quelle
quelle
Antworten:
Ja, ich würde definitiv die zweite Option wählen, aber ich würde ein weiteres Feld als Datumsfeld hinzufügen.
Also fügst du hinzu:
Damit können Sie Zeit für das Wiederherstellen der Aktion geben.
Wenn die Zeit weniger als eine Stunde beträgt, kann die Löschung rückgängig gemacht werden.
Um den gelöschten Eintrag wirklich zu löschen, erstellen Sie einfach eine gespeicherte Prozedur, die jeden Eintrag bereinigt, wobei "delete" auf "true" gesetzt und die Zeit länger als eine Stunde ist, und legen Sie sie als Cron-Tab ab, der alle 24 Stunden ausgeführt wird
Die Stunde ist nur ein Beispiel.
quelle
cleaned
oder etwas anderes) haben , das angibt, dass die mit diesem Datensatz verknüpften Daten ordnungsgemäß und umfassend gelöscht wurden. Der Datensatz kann wiederhergestellt werden, sofern dies nichtcleaned
der Fall ist. In diesem Fall kann er nicht wiederhergestellt werden.deleted_at
, das sowohl die Semantik desdelete
Booleschen als auch dendelete_date
Zeitstempel enthält. Wenndeleted_at
heißtNULL
der Fall handhabendelete
istFALSE
unddelete_date
istNULL
,deleted_at
einen Zeitstempel Griff der Fall enthaltendelete
istTRUE
unddelete_date
enthält einen Zeitstempel, können Sie eine Zeitersparnis, Speicher- und Anwendungslogik.deleted
Feld die Leistung erheblich verbessern kann, wenn Sie nach nicht gelöschten Zeilen suchenIn unseren Anwendungen haben wir nicht wirklich löscht etwas an einem Benutzer fordert ohnehin (unsere Kunden in regulierten Umgebungen, wo etwas zu löschen möglicherweise zu rechtlichen Problemen führen kann).
Wir bewahren die älteren Versionen in einer separaten Prüftabelle auf (also für die Tabelle some_table, in der es auch eine Tabelle namens some_table_audit gibt), die abgesehen von einer zusätzlichen Versionskennung (einem Zeitstempel, wenn Ihre Datenbank Zeitwerte unterstützt, die granular genug sind, eine ganzzahlige Versionsnummer) identisch ist oder UUID, die ein Fremdschlüssel für eine allgemeine Prüftabelle ist (oder so weiter), und die Prüftabelle automatisch per Trigger aktualisieren (damit nicht der gesamte Code, der die Datensätze aktualisiert, auf die Prüfungsanforderung aufmerksam gemacht werden muss).
Diesen Weg:
Wenn Sie anstelle (oder auch) einer ganzzahligen Versionsnummer einen Zeitstempel verwenden, können Sie damit die älteren Kopien nach einer festgelegten Zeit löschen, falls erforderlich. Aber Speicherplatz ist heutzutage relativ billig. Wenn wir keinen Grund haben, alte Daten zu löschen (dh Datenschutzbestimmungen, die besagen, dass Sie Kundendaten nach X Monaten / Jahren löschen sollten), würden wir dies nicht tun.
Diese Antwort gibt es schon seit ein paar Jahren, und seitdem haben sich einige wichtige Dinge, die diese Art der Planung beeinflussen könnten, geändert. Ich werde nicht ins Detail gehen, aber kurz, zum Wohle der Leute, die dies heute lesen:
In SQL Server 2016 wurden "systemversionierte temporale Tabellen" eingeführt, die einen Großteil dieser Arbeit für Sie erledigen, und außerdem wird ein netter syntaktischer Zucker bereitgestellt, um die Erstellung und Pflege historischer Abfragen zu vereinfachen, und sie koordinieren eine Untergruppe von Schemaänderungen zwischen den Tabellen Basis- und Verlaufstabellen. Sie sind nicht ohne Vorbehalte, aber sie sind ein mächtiges Werkzeug für diese Art von Zweck. Ähnliche Funktionen sind auch in anderen DB-Systemen verfügbar.
Änderungen der Datenschutzgesetze, insbesondere die Einführung der DSGVO, können die Frage, wann Daten endgültig gelöscht werden sollten, erheblich verändern. Sie müssen abwägen, inwieweit Daten, die für Prüfungszwecke zu einem späteren Zeitpunkt nützlich (oder sogar gesetzlich vorgeschrieben) sind, nicht gelöscht werden, um die (in den einschlägigen Gesetzen allgemein und spezifisch festgelegten) Rechte der Menschen zu respektieren Ihre Entwürfe. Dies kann ein Problem bei vom System versionierten Zeittabellen sein, da Sie den Verlauf nicht ändern können, um persönliche Daten zu bereinigen, ohne kurzfristige Schemaänderungen vorzunehmen, um die Verlaufsverfolgung zu deaktivieren, während Sie Änderungen vornehmen.
quelle
Bei einer booleschen gelöschten Spalte treten Probleme auf, wenn Ihre Tabelle wächst und sehr groß wird. Ich schlage vor, dass Sie gelöschte Spalten einmal pro Woche (je nach Spezifikation mehr oder weniger) in eine andere Tabelle verschieben. Auf diese Weise haben Sie einen schönen kleinen aktiven Tisch und einen großen Tisch mit allen Aufzeichnungen, die im Laufe der Zeit zusammengetragen wurden.
quelle
Ich würde mit dem separaten Tisch gehen. Ruby on Rails hat ein
acts_as_versioned
Plugin, das im Grunde genommen eine Zeile mit dem Postfix in einer anderen Tabelle speichert,_version
bevor es aktualisiert wird. Während Sie dieses genaue Verhalten nicht benötigen, sollte es auch für Ihren Fall funktionieren (vor dem Löschen kopieren).Wie bei @Spredzy würde ich auch empfehlen, eine
delete_date
Spalte hinzuzufügen , um programmgesteuert Datensätze zu löschen, die nach X Stunden / Tagen / was auch immer nicht wiederhergestellt wurden.quelle
Die Lösung, die wir intern für diese Angelegenheit verwenden, besteht darin, eine Statusspalte mit einigen fest codierten Werten für einige bestimmte Zustände des Objekts zu haben: Gelöscht, Aktiv, Inaktiv, Offen, Geschlossen, Gesperrt - jeder Status hat eine Bedeutung, die in der Anwendung verwendet wird. Aus Sicht von db entfernen wir keine Objekte, wir ändern nur den Status und behalten den Verlauf für jede Änderung in der Objekttabelle bei.
quelle
Wenn Sie sagen, dass "die letztere Lösung zusätzliche Anwendungslogik zum Ignorieren der 'gelöschten' Datensätze erfordern würde", besteht die einfache Lösung darin, eine Ansicht zu haben, die sie herausfiltert.
quelle
Ähnlich wie von Spredzy vorgeschlagen, verwenden wir in all unseren Anwendungen ein Zeitstempelfeld zum Löschen. Der Boolesche Wert ist überflüssig, da der eingestellte Zeitstempel anzeigt, dass der Datensatz gelöscht wurde. Auf diese Weise ergänzt unser PDO
AND (deleted IS NULL OR deleted = 0)
die select-Anweisungen immer, es sei denn, das Modell fordert ausdrücklich die Einbeziehung gelöschter Datensätze an.Wir sammeln derzeit keine Daten mit Ausnahme von Tabellen, die Blobs oder Texte enthalten. Der Abstand ist trivial, wenn die Datensätze gut normalisiert sind, und die Indizierung des
deleted
Felds wirkt sich nur begrenzt auf die Auswahlgeschwindigkeit aus.quelle
Alternativ können Sie den Benutzern (und Entwicklern) die Verantwortung überlassen und eine Abfolge von "Sind Sie sicher?", "Sind Sie sich sicher?" und "Bist du dir absolut sicher?" Fragen, bevor der Datensatz gelöscht wird. Mild witzig, aber eine Überlegung wert.
quelle
Ich bin es gewohnt, Tabellenzeilen mit Spalten wie "DeletedDate" zu sehen, und ich mag sie nicht. Der Begriff "gelöscht" bedeutet, dass die Eingabe nicht an erster Stelle hätte erfolgen dürfen. Sie können praktisch nicht aus der Datenbank entfernt werden, aber ich möchte nicht, dass sie mit meinen aktuellen Daten in Kontakt kommen. Logisch gelöschte Zeilen sind per Definition kalte Daten, es sei denn, jemand möchte ausdrücklich gelöschte Daten sehen.
Darüber hinaus muss jede geschriebene Abfrage sie ausdrücklich ausschließen und Indizes müssen sie ebenfalls berücksichtigen.
Was ich sehen möchte, ist eine Änderung auf der Ebene der Datenbankarchitektur und der Anwendungsebene: Erstellen Sie ein Schema mit dem Namen "gelöscht". Jede benutzerdefinierte Tabelle hat im Schema "Gelöscht" ein identisches Äquivalent mit einem zusätzlichen Feld, das Metadaten enthält - den Benutzer, der sie wann gelöscht hat. Fremdschlüssel müssen erstellt werden.
Als nächstes werden Löschvorgänge zu Einfügelöschvorgängen. Zuerst wird die zu löschende Zeile in das entsprechende Schema eingefügt. Die betreffende Zeile in der Haupttabelle kann dann gelöscht werden. Zusätzliche Logik muss jedoch irgendwo entlang der Linie hinzugefügt werden. Fremdschlüsselverletzungen können behandelt werden.
Fremdschlüssel müssen ordnungsgemäß behandelt werden. Es ist keine gute Praxis, eine Zeile logisch löschen zu lassen, deren primäre / eindeutige Spalte jedoch Spalten in anderen Tabellen enthält, die darauf verweisen. Das sollte sowieso nicht passieren. Ein regulärer Job kann Witwenzeilen entfernen (Zeilen, deren Primärschlüssel trotz eines Fremdschlüssels keine Referenzen in anderen Tabellen enthalten). Dies ist jedoch eine Geschäftslogik.
Der Gesamtnutzen ist die Reduzierung der Metadaten in der Tabelle und die damit verbundene Leistungsverbesserung. Die Spalte 'deletedDate' besagt, dass diese Zeile eigentlich nicht hier sein sollte. Der Einfachheit halber lassen wir sie dort und überlassen sie der SQL-Abfrage. Wenn eine Kopie der gelöschten Zeile in einem "gelöschten" Schema gespeichert wird, enthält die Haupttabelle mit den aktuellen Daten einen höheren Prozentsatz aktueller Daten (sofern diese rechtzeitig archiviert werden) und weniger unnötige Metadatenspalten. Indizes und Abfragen müssen dieses Feld nicht mehr berücksichtigen. Je kürzer die Zeilengröße, desto mehr Zeilen können auf eine Seite gepasst werden, desto schneller kann SQL Server arbeiten.
Der Hauptnachteil ist die Größe der Operation. Es gibt jetzt zwei Operationen anstelle von einer sowie die zusätzliche Logik und Fehlerbehandlung. Dies kann zu mehr Sperren führen, als das Aktualisieren einer einzelnen Spalte andernfalls erfordern würde. Die Transaktion hält die Tabelle länger gesperrt, und es handelt sich um zwei Tabellen. Das Löschen von Produktionsdaten wird, zumindest nach meiner Erfahrung, nur selten durchgeführt. Trotzdem haben 7,5% von fast 100 Millionen Einträgen in einer der Haupttabellen einen Eintrag in der Spalte "DeletedDate".
Zur Beantwortung der Frage müsste die Anwendung die Funktion "Wiederherstellen" kennen. Dies müsste einfach in umgekehrter Reihenfolge geschehen: Fügen Sie die Zeile aus dem 'gelöschten' Schema in die Haupttabelle ein und löschen Sie dann die Zeile aus dem 'gelöschten Schema. Auch hier ist eine zusätzliche Logik- und Fehlerbehandlung erforderlich, um Fehler, Probleme mit Fremdschlüsseln und dergleichen zu vermeiden.
quelle