Eine Datenbank vergisst nichts. Aber sie versteht auch nichts.
Das ist kein Fehler. Das ist ihr Wesen. Sie speichert, was du ihr gibst. Sie löscht, was du ihr befiehlst. Und sie schweigt, wenn du die falsche Frage stellst. Die Verantwortung, was vergessen werden darf und was nicht, liegt immer bei dir — nicht beim System.
Ich habe in vielen Projekten gesehen, wie dieser Unterschied übersehen wird. Ein Knopf heißt "Löschen". Der Nutzer klickt. Die Zeile verschwindet aus der Oberfläche. Und irgendwo in einer PostgreSQL-Tabelle lebt der Datensatz weiter — oder er ist wirklich weg, für immer, ohne Protokoll, ohne Spur. Beides kann falsch sein.
Löschen ist keine binäre Entscheidung
Es gibt zwei grundlegende Strategien: Hard Delete und Soft Delete. Beide klingen technisch. Aber hinter ihnen stecken Fragen, die weit über Code hinausgehen.
Ein Hard Delete ist endgültig. DELETE FROM users WHERE id = $1 — die Zeile ist weg. Kein Recovery, kein Rückblick, kein "Wann wurde das eigentlich gelöscht?" Für bestimmte Daten ist das genau richtig. Die DSGVO verlangt in manchen Fällen explizit das vollständige Entfernen personenbezogener Daten. Das Recht auf Vergessenwerden ist kein Feature — es ist eine gesetzliche Pflicht.
Ein Soft Delete hingegen markiert. Die Zeile bleibt. Sie bekommt ein Timestamp-Feld, einen Boolean, eine Spalte deleted_at. Sie ist "logisch gelöscht", aber physisch vorhanden.
-- Soft Delete: Spalte hinzufügen
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMPTZ DEFAULT NULL;
-- Löschen bedeutet jetzt: markieren
UPDATE users
SET deleted_at = NOW()
WHERE id = $1;
-- Alle aktiven Nutzer
SELECT * FROM users
WHERE deleted_at IS NULL;
-- Alle gelöschten Nutzer (für Audit, Admin, Recovery)
SELECT * FROM users
WHERE deleted_at IS NOT NULL;
Das klingt elegant. Und es ist elegant — solange du weißt, was du damit tust. Denn ein Soft Delete ist keine Datenschutzlösung. Es ist eine Architekturentscheidung. Wer Zugriff auf die Datenbank hat, sieht alles. Wer die falsche Query schreibt, zeigt dem Nutzer seine eigenen "gelöschten" Daten wieder an.
Das Audit-Log: Gedächtnis mit Absicht
Es gibt Dinge, die du nicht vergessen darfst. Nicht weil du es willst, sondern weil Systeme ohne Gedächtnis blind werden.
Wer hat was wann geändert? Welcher Admin hat einen Datensatz bearbeitet? Welche Preise galten zum Zeitpunkt einer Bestellung? Diese Fragen kommen immer dann, wenn es wehtut — bei einem Rechtsstreit, bei einem Supportfall, bei einem Sicherheitsvorfall.
Ein Audit-Log ist kein Luxus. Es ist das Rückgrat des Vertrauens in ein System.
-- Audit-Log Tabelle
CREATE TABLE audit_log (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
table_name TEXT NOT NULL,
record_id UUID NOT NULL,
action TEXT NOT NULL CHECK (action IN ('INSERT', 'UPDATE', 'DELETE')),
old_data JSONB,
new_data JSONB,
changed_by UUID REFERENCES users(id),
changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Trigger-Funktion für automatisches Logging
CREATE OR REPLACE FUNCTION log_changes()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log (table_name, record_id, action, old_data, new_data, changed_by)
VALUES (
TG_TABLE_NAME,
COALESCE(NEW.id, OLD.id),
TG_OP,
CASE WHEN TG_OP = 'INSERT' THEN NULL ELSE row_to_json(OLD)::JSONB END,
CASE WHEN TG_OP = 'DELETE' THEN NULL ELSE row_to_json(NEW)::JSONB END,
current_setting('app.current_user_id', true)::UUID
);
RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;
-- Trigger aktivieren
CREATE TRIGGER users_audit
AFTER INSERT OR UPDATE OR DELETE ON users
FOR EACH ROW EXECUTE FUNCTION log_changes();
Dieser Trigger schreibt bei jeder Änderung automatisch einen Eintrag. Er vergisst nichts. Er urteilt nicht. Er protokolliert.
Wichtig: Das Audit-Log selbst darf nicht veränderbar sein. Keine Updates, keine Deletes. Es ist ein append-only Protokoll. Wer das Audit-Log löschen kann, kann die Vergangenheit umschreiben.
DSGVO und Datenarchitektur: Zwei Welten, die zusammengehören
Die DSGVO ist kein Feind guter Architektur. Sie ist ein Spiegel. Sie zwingt dich, Fragen zu stellen, die du ohnehin stellen solltest: Warum speichere ich das? Wie lange brauche ich es? Wer darf es sehen?
Für KMU in Österreich bedeutet das konkret: Personenbezogene Daten brauchen ein Verfallsdatum — nicht nur im Datenschutzdokument, sondern in der Datenbank selbst.
-- Retention Policy: Nutzer-Daten nach 3 Jahren anonymisieren
UPDATE users
SET
email = 'anonymized_' || id || '@deleted.invalid',
first_name = 'Gelöscht',
last_name = 'Gelöscht',
phone = NULL,
deleted_at = NOW()
WHERE
deleted_at IS NOT NULL
AND deleted_at < NOW() - INTERVAL '3 years';
Das ist kein Hard Delete. Es ist Anonymisierung. Der Datensatz bleibt für referenzielle Integrität erhalten — Bestellungen, Logs, Verknüpfungen bleiben konsistent. Aber die Person dahinter ist nicht mehr rekonstruierbar.
Das ist der Unterschied zwischen Vergessen und Vernichten. Manchmal ist Vergessen genug.
Speicherbegrenzung ist keine technische Frage
Ich erlebe es regelmäßig: Ein System wächst. Die Datenbank wächst. Niemand fragt, warum. Niemand fragt, was davon noch gebraucht wird.
Eine Datenbank ist kein Archiv. Ein Archiv hat Regeln, wer wann was einsehen darf. Eine Datenbank ohne Governance ist ein Lager ohne Inventar — du weißt, dass etwas drin ist, aber nicht mehr, was.
Für KMU ist das besonders kritisch. Kleine Teams, wenig Zeit für Datenpflege, schnell wachsende Tabellen. Die Lösung ist nicht mehr Speicher. Die Lösung ist Disziplin in der Datenmodellierung — von Anfang an.
Drei Fragen, die ich bei jedem neuen Datenmodell stelle:
- Wann darf dieser Datensatz gelöscht werden? — Nicht "kann", sondern "darf". Rechtlich, fachlich, technisch.
- Wer muss informiert werden, wenn er gelöscht wird? — Andere Systeme, andere Tabellen, andere Teams.
- Was passiert mit allem, was auf diesen Datensatz zeigt? — Foreign Keys, Logs, Reports.
Diese Fragen sind unbequem. Sie verlangsamen den ersten Entwicklungstag. Sie verhindern den zehnten Notfall.
Was bleibt
Jede Zeile, die du in eine Datenbank schreibst, ist eine Entscheidung. Jede Zeile, die du nicht löschst, ist eine weitere Entscheidung. Und jede Zeile, die du löschst ohne zu wissen warum, ist ein Risiko.
Soft Delete oder Hard Delete — das ist nicht die eigentliche Frage. Die eigentliche Frage ist: Hast du entschieden, was dieses System erinnern soll und was nicht? Oder hat es das stillschweigend für dich getan?
Eine Datenbank hat kein Gewissen. Das ist kein Mangel. Das ist eine Einladung.
Die Verantwortung, was vergessen wird — die liegt bei dir.



