Ist es eine schlechte Praxis, eine Spalte "Datensatzstatus" in einer Datenbanktabelle zu haben?

12

Ich muss zunächst klarstellen, dass die Statusspalte nicht den Status eines realen Elements widerspiegeln soll, das durch den Datensatz (Zeile) in der Tabelle dargestellt wird. Vielmehr soll der Status des Datensatzes selbst angezeigt werden.

Es kann so einfach wie Aktiv / Inaktiv oder kompliziert wie Genehmigt / Gelöscht / Gesperrt / Ausstehend / Abgelehnt usw. sein. Der Status kann in einer booleschen / kurzen Ganzzahlspalte oder einer Einzelzeichenspalte mit Zuordnungen wie true/ 1= Aktiv oder gespeichert werden A= Genehmigt.

Die Grundidee besteht darin, in der Anwendung eine Unterstützung für den Papierkorb- / Papierkorb-ähnliche Wiederherstellung bereitzustellen (und diese in der Datenbank zu simulieren). Wenn es eine Front-End-GUI oder eine andere Schnittstelle gibt, die einem Benutzer das "Löschen" von Datensätzen ermöglichen soll, wird der Datensatz in der Tabelle nicht tatsächlich gelöscht, sondern der Datensatzstatus wird einfach in Inaktiv oder Gelöscht geändert. Wenn die Schnittstelle Datensätze abruft, werden immer die Datensätze abgerufen, die nur der Bedingung entsprechen, dass der Status Aktiv oder Genehmigt lautet.

Wenn der Benutzer einen Fehler macht und der "gelöschte" Datensatz (aus Benutzersicht) wiederhergestellt werden muss, kann ein Datenbankadministrator den Datensatz problemlos auf "Aktiv" oder "Genehmigt" zurücksetzen. Dies ist besser, als nach Sicherungen zu suchen und hoffentlich den ursprünglichen Datensatz zu finden Dort. Über die Benutzeroberfläche selbst kann der Benutzer gelöschte Datensätze in einer separaten Ansicht anzeigen und bei Bedarf wiederherstellen oder sogar dauerhaft löschen (Löschen des tatsächlichen Datensatzes).

Meine Fragen:

  • Ist das eine gute oder eine schlechte Praxis?
  • Beeinflusst es die Normalisierung der Daten?
  • Was sind die potenziellen Gefahren?
  • Gibt es eine alternative Methode, um dasselbe Ziel zu erreichen? (siehe Anmerkung)
  • Wie kann die Datenbank eindeutige Einschränkungen für die Daten nur für einen bestimmten Status erzwingen (für andere Status jedoch eine beliebige Anzahl von Duplikaten zulassen)?
  • Warum bieten Datenbanken keine "Papierkorb" -Funktion oder Tabellenverfolgung / -wiederherstellung von Haus aus, sodass die Benutzeroberflächen die tatsächlichen Datensätze problemlos löschen können?

Hinweis: Ich habe gelesen, dass eine separate Verlaufstabelle verwaltet werden muss, was jedoch hinsichtlich des Speichers und der Notwendigkeit, Trigger zu generieren und die Trigger mit dem Schema der verfolgten Tabelle auf dem neuesten Stand zu halten, schlimmer zu sein scheint.

ADTC
quelle
Das Problem mit den eindeutigen Einschränkungen (die Sie bereits genannt haben) ist genau, warum Verlaufstabellen häufig vorzuziehen sind. Sie können die eindeutigen Schlüsseleinschränkungen für die Originaltabellen beibehalten und nicht zur Verlaufstabelle hinzufügen. Darüber hinaus erleichtern separate Verlaufstabellen das Hinzufügen bestimmte (DB-abhängige) Speicheroptionen für sie zu verwenden, sodass sie in Bezug auf den Speicher oft besser sind , nicht schlechter. Wenn Sie viele dieser Tabellen haben, sollten die Trigger- und Verlaufstabellen nicht von Hand geschrieben, sondern generiert werden, um das Problem zu lösen, wie Sie sie "auf dem neuesten Stand" halten können.
Doc Brown

Antworten:

5

Ich kenne das als "Soft Delete"; Nur einen Datensatz als "gelöscht" markieren, obwohl dies nicht der Fall ist.

Ist das eine gute oder eine schlechte Praxis?

Es hängt davon ab, ob.
Wenn dies etwas ist, das Ihre Benutzer [sehr] brauchen, dann ist es wahrscheinlich eine gute Sache. In den allermeisten Fällen würde ich jedoch argumentieren, dass es [viel] Overhead für wenig Nutzen hinzufügt.

Beeinflusst es die Normalisierung der Daten?

Nein, aber dies wirkt sich auf die Indizierung dieser Daten aus.
Stellen Sie sicher, dass Sie die Spalte "Gelöscht" in Ihre Indizes aufnehmen, damit diese Zeilen in Ihren Abfragen so früh wie möglich ausgeschlossen werden.

Was sind die potenziellen Gefahren?

Ihre Daten werden etwas komplexer. Alles, was sich irgendwo in der Nähe der Daten befindet, muss über diese zusätzlichen "nicht wirklich vorhandenen" Datensätze "Bescheid wissen". Oder Sie müssen Ansichten für die Tabellen erstellen, die diese Zeilen ausschließen, und diese Ansichten beispielsweise in Ihrem Berichterstellungstool Ihrer Wahl verwenden.

Ihre Datenbank kann an Größe zunehmen. Wenn Sie diese Zeilen nicht wirklich löschen, sind sie immer noch vorhanden und belegen Speicherplatz. Dies kann ein Problem sein oder auch nicht, insbesondere, da Sie sie in Ihre Indizes aufgenommen haben, sodass der von ihnen belegte Speicherplatz vervielfacht wird.

Gibt es eine alternative Methode, um dasselbe Ziel zu erreichen? (siehe Anmerkung)

Nicht wirklich, nein.

Wie kann die Datenbank eindeutige Einschränkungen für die Daten nur für einen bestimmten Status erzwingen (für andere Status jedoch eine beliebige Anzahl von Duplikaten zulassen)?

Nicht einfach. Die deklarative referenzielle Integrität (Fremdschlüsselklauseln) ist der sauberste Weg, dies zu implementieren, und es ist für Dinge wie Berichterstellungstools einfach, diese Regeln aufzunehmen, um die Beziehungen zwischen Tabellen zu bestimmen. Solche Regeln gelten für alle Datensätze, unabhängig vom "Status" (und daran führt kein Weg vorbei).

Die Alternative ist die Verwendung von Triggern, Ausschnitten aus dem Prozedurcode, die die referenzielle Integrität zwischen Tabellen erzwingen und alle cleveren, bedingten Aufgaben erledigen, die Sie benötigen. Das ist gut für Ihren speziellen Fall, aber die meisten Vorteile von Declarative RI gehen aus dem Fenster - es gibt keine [extern] erkennbaren Beziehungen zwischen Ihren Tabellen. Das ist alles "versteckt" in den Auslösern.

Warum bieten Datenbanken keine "Papierkorb" -Funktion oder Tabellenverfolgung / -wiederherstellung von Haus aus, sodass die Benutzeroberflächen die tatsächlichen Datensätze problemlos löschen können?

Warum sollten sie?

Dies sind schließlich Datenbanken, keine Dateisysteme oder Tabellenkalkulationen.

Was sie tun, können sie sehr, sehr gut.

Was sie nicht tun, war wahrscheinlich nicht sehr gefragt.

Phill W.
quelle
Gute Antwort, aber es gibt alternative Möglichkeiten, z. B. die Zeilen in eine Sicherungstabelle zu verschieben, aus der Sie sie wiederherstellen können. Die Sicherungstabelle kann minimale Indizes haben. Dies minimiert die Probleme, die Sie bei der vorhandenen Vorgehensweise feststellen (größerer Index, potenzielle Verwirrung für Benutzer der Tabelle usw.), fügt jedoch offensichtlich die Tatsache hinzu, dass Sie eine andere Tabelle pflegen müssen (und bedeutet, dass die Einträge in Fremdschlüsselreferenzen geschrieben werden). Es gibt noch einige andere Optionen - aber die, die in den Sinn kommen, sind alle benutzerdefinierte Implementierungen, die in solchen Fällen nicht von jeder SQL-Datenbank allgemein angeboten werden.
Frank Hopkins
9

Es ist eine Übung. Ob es gut oder schlecht ist, hängt stark von Ihrer Anwendung ab und davon, wie häufig Sie wirklich ein "Undelete" ausführen müssen / möchten. Ich wäre ziemlich zweifelhaft, ob ich diese Art von Spalten für jede Tabelle in das System aufnehmen möchte - es ist sehr unwahrscheinlich, dass Sie wirklich die Mühe machen, Undelete für jede Tabelle im System zu implementieren. Und es ist eine Implementierung erforderlich. In den allermeisten Fällen wird nicht eine einzelne Zeile aus einer einzelnen Tabelle wiederhergestellt, sondern es werden untergeordnete Tabellen durchsucht, um die Zeilen wiederherzustellen und die zugehörigen Tabellen zu aktualisieren.

Bei den meisten anderen Fragen ist die Implementierung stark abhängig. Beispielsweise bietet Oracle verschiedene Methoden, um alle Änderungen an einer Tabelle nachzuverfolgen. Flashback Data Archive (FDA, auch als Total Recall bezeichnet) ist der neueste Ansatz, um eine vollständige Historie jeder Version einer Zeile und eine datenbankinterne Archivierung für die Implementierung zu verwalten das Soft-Delete-Muster. Andere Datenbanken bieten möglicherweise andere Möglichkeiten zum Implementieren des Musters. Abhängig von der Datenbank und der Art und Weise, wie Sie das vorläufige Löschen implementieren, hat dies verschiedene Auswirkungen auf die Leistung, ob und wie Einschränkungen erzwungen werden können usw. Wenn es sich um Oracle handelt, können Sie beispielsweise eine Menge mit funktionsbasierten Indizes tun In SQL Server können Sie häufig gefilterte Indizes für ähnliche Zwecke verwenden.

Justin Cave
quelle
Oracle Flashback ist genau die ideale Lösung für das, was ich will. Schade, dass es Oracle-geschützt ist.
ADTC
4

In MRP / ERP-Systemen wird häufig das Feld "Zum Löschen vorgemerkt" verwendet.

Beispielsweise kann es sinnvoll sein, einen Teil- oder Bestandsdatensatz zu markieren, der nicht mehr als inaktiv verkauft wird, mit dem jedoch noch ausstehende Bestellungen verbunden sind. Eine echte Löschung des Datensatzes kann sich auf noch nicht versendete Aufträge, noch nicht gebuchte Ledger-Einträge, Verlaufstabellen, die erst zum Monatsende erstellt werden, usw. auswirken. Viele Systeme können das Löschen eines Datensatzes nur zulassen, wenn eine Serie erfolgreich abgeschlossen wurde von Validierungen gegen andere Tabellen. Wenn Sie Löschungen durch Ihre Beziehungen kaskadieren, kann ein echtes Löschen sogar noch destruktiver sein.

Indem Sie den Datensatz zum Löschen markieren, setzen Sie stattdessen eine eindeutige Absichtsmarkierung in den Datensatz. Später kann ein geplanter Task den Datensatz löschen, wenn überprüft wird, dass nicht mehr alle zugehörigen Tabellen auf ihn verweisen.

Ein ähnlicher Fall könnte für dieses Merkmal bei einer Kundentabelle und anderen "Langzeittabellen" gemacht werden. Es ist sogar bei volatileren Tabellen wie Aufträgen sinnvoll, obwohl der Name der Flagge so etwas wie "versendet" oder "storniert" werden kann. Es hat die gleiche Funktion: Lösche es nicht in dieser Sekunde, sondern verwende es als Flag für das Löschprogramm, damit es versucht, das Löschen des Datensatzes in der Zukunft zu validieren.

Mike unterstützt Monica
quelle
3

Als alternative Lösung ermöglicht die Verwendung von Event-Sourcing ähnliche Ziele, ohne die Tabellenstruktur zu komplizieren, obwohl der Code zum Ändern Ihrer Daten dadurch etwas komplexer wird, da Sie die Änderung in ein Ereignis schreiben müssen, das in einem Ereignisverlauf gespeichert werden kann . Auf diese Weise können Sie die Datenbank zu jedem Zeitpunkt neu erstellen, was eine sehr nützliche Funktion sein kann.

(Ich glaube nicht, dass Sie dies mit "Verlaufstabelle" gemeint haben. Ich glaube, Sie haben damit gemeint, dass Sie einfach geänderte oder gelöschte Datensätze in eine andere Tabelle kopieren, bevor Sie sie ändern.)

Jules
quelle
Interessantes Konzept. Ich werde untersuchen, wie dies umgesetzt werden kann.
ADTC
1

Ich sehe und benutze dieses Muster häufig für diese Anwendungsfälle:

  • Metadaten, in denen Sie nur die Werte anzeigen möchten, die heute gültig sind. Um beispielsweise aus einer Liste von Autoherstellern in einer Dropdown-Liste auszuwählen, in der = 1 aktiviert ist, lauten die Tabellenwerte für ID, VALUE, ENABLED 1, 'Ford', 1 und 2, 'Edsel', 0, 3, 'Toyota'. , 1 gibt nur die Auswahl von Ford und Toyota
  • für ein Fallmanagementsystem, bei dem das Paradigma lautet, dass sich ein Fall immer nur in einem Zustand befinden kann. In diesem Fall wurde die Umschaltspalte CURRENT genannt, wobei die Werte 0 oder 1 durch Prüfbedingungen erzwungen wurden. Wenn ein Fall von einem Zustand in einen anderen wechselt, aktualisiert die Anwendung das CURRENT-Flag des alten Zustands auf 0 und das neue auf 1

Das Problem besteht darin, die Datenintegrität zu erzwingen, wenn mehr als eine Anwendung oder ein Webdienst in Tabellen schreibt. Wie stellen Sie sicher, dass es für einen Fall nur einen aktuellen Status gibt? Wie Justin Cave betont, kann dies in Oracle durch Erstellen eines virtuellen Indexes auf der Grundlage einer Funktion erfolgen, jedoch mit zusätzlichem Aufwand für ein ursprünglich einfaches Konzept.

Kevin
quelle
1

Dies ist eine gute Vorgehensweise, wenn Sie Ihre Daten für die Berichterstellung verwenden möchten (für jede ausreichend große Anwendung sind Berichte erforderlich).

Um Ihre Anwendung zu beschleunigen, sollten Sie Berichterstellungstools nicht in Ihrer Datenbank ausführen. Als solches müssten Sie eine Kopie / Synchronisierung mit einer anderen Datenbank durchführen.

Ich benutze recordStatusnur zwei Zustände ACTIVEoder CANCELLEDin Kombination mit einem lastUpdatedOnZeitstempel. Ich benutze recordStatuseher als statuswas normalerweise eine geschäftliche Bedeutung hat.

Wenn ich die Berichtsdatenbank mit der Anwendung synchronisiere, überprüfe ich anhand eines Filters lastUpdatedOn, welche auf der Berichtsseite ersetzt werden sollen.

Auf der Berichtsseite werden die Felder recordStatusoder nicht lastUpdatedOnangezeigt, da normalerweise nicht darüber berichtet wird. Wenn ein CANCELLEDStatus angezeigt wird, lösche ich den Datensatz auf der Berichtsseite, sodass nur aktive Datensätze vorhanden sind.

Dies kann auf andere Arten von Speichern wie Archive oder Sicherungen ausgedehnt werden, bei denen eine nahezu vollständige Synchronisierung erforderlich ist. Die Berichterstattung ist jedoch der häufigste Zweck.

Beachten Sie Ihr Beispiel Approved, New, Pendingist keine gute Idee , als ein gemeinsames Feld zu setzen , da das ein Geschäft soll es weise nur, wo es Sinn macht Geschäft geht Bedeutung hat.

Verwenden Sie für "Gesperrt" versionNodie Option, die eine optimistische Sperre für Ihren Datensatz bietet.

Eine andere Option recordStatusist recordActiveund hat es als eine gespeichert, booleandie weniger Speicherplatz und weniger Indizierung beansprucht, aber ich wäre besorgt über zukünftige Bedürfnisse, die Sie möglicherweise nicht vorhersehen.

Archimedes Trajano
quelle