Zum Inhalt

Relationale Datenbank-Grundlagen & ACID-Garantien: Von relationaler Algebra bis zum physischen Speicher

Erstellt: 08.11.2026  ·  Zuletzt aktualisiert: 08.11.2026  ·  Nejat Hakan

Management Summary: Moderne Unternehmensanwendungen vertrauen auf relationale Datenbankverwaltungssysteme (RDBMS) wie PostgreSQL und MariaDB/MySQL, um die Korrektheit geschäftskritischer Daten auch unter hoher Last und bei unvorhergesehenen Stromausfällen zu garantieren. Während Entwickler mit Tabellen, Spalten und deklarativen SQL-Abfragen arbeiten, operiert die Datenbank-Engine im Hintergrund auf mathematischer Mengentheorie und systemnahen Speicherprimitiven des Linux-Kernels. Dieser Leitfaden beleuchtet die architektonische Brücke zwischen Edgar F. Codds relationalem Modell und der physischen Speicherschicht: Wie die vier ACID-Säulen (Atomarität, Konsistenz, Isolation, Dauerhaftigkeit) durch Write-Ahead Logging (WAL), Multi-Version Concurrency Control (MVCC) und synchrone fsync()-Aufrufe des Betriebssystems durchgesetzt werden.

  • Das relationale Modell


    Logische Abfragen von physischer Speicherung entkoppeln: Daten als mathematische Relationen (Tabellen), Tupel (Zeilen) und Attribute (Spalten) abbilden.

  • Atomarität & WAL


    „Alles-oder-Nichts“-Garantie: Abgebrochene Transaktionen rückstandslos verwerfen und unbestätigte Zustände über das Write-Ahead-Log atomar auflösen.

  • Konsistenz & Constraints


    Geschäftsinvarianten direkt in der Datenbank-Engine erzwingen: Fremdschlüssel, Check-Constraints und Unique-Indizes deterministisch validieren.

  • Isolation & Dauerhaftigkeit


    Race Conditions durch MVCC-Snapshot-Isolation eliminieren und Absturzsicherheit durch synchronen Kernel-fsync()-Flush auf NVMe garantieren.


1. Das relationale Paradigma: Logische Abstraktion vs. physischer Speicher

Im Jahr 1970 veröffentlichte der Mathematiker und Informatiker Edgar F. Codd bei IBM eine bahnbrechende Arbeit über das relationale Modell. Vor Codd basierten Datenbanken auf hierarchischen oder Netzwerk-Architekturen (wie CODASYL), bei denen der Anwendungscode explizite physische Festplattenzeiger und Speicheradressen traversieren musste. Änderte sich ein Index oder die Blockgröße auf der Festplatte, stürzten die Anwendungen ab.

Codds revolutionäre Innovation war die physische Datenunabhängigkeit: Die vollständige Entkopplung der logischen Datenabfrage von der physischen Organisation und Speicherung auf dem Datenträger.

%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
    APP["Client-Anwendung<br/>(Deklaratives SQL via TCP)"]
    PARSE["Parser & Rewriter<br/>(Syntax & View-Expansion)"]
    OPT["Cost-Based Optimizer<br/>(Ausführungsplan-Berechnung)"]
    EXEC["Execution Engine<br/>(Index-Scans, Joins, Locks)"]
    BUF["Shared Buffer Pool<br/>(In-Memory 8/16 KiB Pages)"]
    WAL["WAL / Redo-Puffer<br/>(Append-Only-Log)"]
    DISK["Physischer NVMe-Speicher<br/>(Dateien & WAL)"]

    APP --> PARSE
    PARSE --> OPT
    OPT --> EXEC
    EXEC <--> BUF
    EXEC --> WAL
    BUF <--> DISK
    WAL --> DISK

Relationale Terminologie vs. SQL-Terminologie

In der formalen relationalen Algebra unterscheidet sich die Nomenklatur leicht von den gängigen Begriffen im SQL-Alltag:

Relationale Algebra SQL-Entsprechung Physischer Speicher Beschreibung
Relation Tabelle / View Heap-Datei / Clustered Index Eine ungeordnete Menge von Tupeln mit identischen Attributen.
Tupel Zeile / Datensatz Data-Page-Slot / Heap-Tuple Eine konkrete Instanz mit geordneten Attributwerten.
Attribut Spalte / Feld Byte-Offset im Tupel-Header Eine benannte, stark typisierte Eigenschaft einer Relation.
Domäne Datentyp + Constraints Maschinentyp (INT4, UUID) Die Menge aller zulässigen atomaren Werte für ein Attribut.
Grad (Stelligkeit) Spaltenanzahl Schema-Metadaten Die Gesamtzahl der Attribute, die das Schema definieren.
Kardinalität Zeilenanzahl Statistik-Sampler (pg_class.reltuples) Die aktuelle Anzahl der vorhandenen Tupel in der Relation.

2. Die vier ACID-Säulen im Detail

Jede geschäftskritische Transaktion basiert auf dem ACID-Garantievertrag zwischen dem RDBMS und dem Linux-Betriebssystem.

A. Atomarität (Atomicity): Die Alles-oder-Nichts-Garantie

Atomarität garantiert, dass eine Transaktion aus mehreren SQL-Befehlen (INSERT, UPDATE, DELETE) als eine einzige, unteilbare Arbeitseinheit ausgeführt wird. Entweder werden alle Änderungen erfolgreich und dauerhaft angewendet, oder die gesamte Operation wird zurückgerollt, sodass die Datenbank exakt im Zustand vor Beginn der Transaktion verbleibt.

-- Datei: /opt/db-ops/atomicity_bank_transfer.sql
BEGIN;

-- Konto A belasten
UPDATE bank_accounts 
SET balance_cents = balance_cents - 50000 
WHERE account_id = 'ACC-001' AND balance_cents >= 50000;

-- Konto B gutschreiben
UPDATE bank_accounts 
SET balance_cents = balance_cents + 50000 
WHERE account_id = 'ACC-002';

-- Bricht der Server vor COMMIT ab, garantiert Atomarität, dass niemals nur Konto A belastet wird
COMMIT;

Technische Umsetzung der Atomarität

Die Datenbank modifiziert Tabellenseiten während einer Transaktion nicht direkt an Ort und Stelle auf der Festplatte. In PostgreSQL wird jede Zeilenversion mit Transaktions-IDs versehen (xmin für das Erstellen, xmax für das Löschen oder Ändern) und in den Pufferpool geschrieben. Wird die Transaktion mit ROLLBACK abgebrochen oder stürzt der Server vor dem COMMIT ab, wird der Status der Transaktion im Commit-Log (pg_xact) als abgebrochen (ABORTED) markiert. Dadurch sind alle von dieser Transaktion erzeugten Datenzeilen für sämtliche anderen Verbindungen permanent unsichtbar.

B. Konsistenz (Consistency): Erhaltung der Invarianten

Konsistenz stellt sicher, dass eine Transaktion die Datenbank nur von einem gültigen Zustand in einen anderen gültigen Zustand überführen kann. Alle definierten Schemaregeln, Integritätsbedingungen und relationalen Abhängigkeiten müssen zu jedem Zeitpunkt erfüllt sein.

%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
    T_START["Transaktion startet<br/>Zustand: Gültig"]
    CHECK1["Datentypen validieren<br/>(z. B. Zahlenformate)"]
    CHECK2["NOT NULL & CHECK prüfen<br/>(z. B. Kontostand >= 0)"]
    CHECK3["Fremdschlüssel prüfen<br/>(Elternzeile existiert)"]
    CHECK4["Unique-Indizes prüfen<br/>(Keine Dubletten)"]
    DEC{"Alle Invarianten<br/>erfüllt?"}
    T_COMMIT["Transaktion bestätigt<br/>Zustand: Gültig"]
    T_ABORT["Transaktion abgebrochen<br/>Engine wirft Fehler"]

    T_START --> CHECK1
    CHECK1 --> CHECK2
    CHECK2 --> CHECK3
    CHECK3 --> CHECK4
    CHECK4 --> DEC
    DEC -->|Ja| T_COMMIT
    DEC -->|Nein| T_ABORT

Im Gegensatz zu Validierungen im Anwendungscode (die durch parallele Hintergrundskripte oder Direkteingaben umgangen werden können) greift die Konsistenzprüfung direkt auf Datenbankebene: - Domänen-Prüfungen: Ablehnung ungültiger Maschinenwerte (z. B. ungültiges Datumsformat oder Überlauf). - Check-Constraints (CHECK): Mathematische Wertebereiche garantieren (z. B. CHECK (price_cents > 0)). - Referenzielle Integrität (FOREIGN KEY): Verhindert verwaiste Datensätze, wenn Eltern-Entitäten gelöscht oder verschoben werden. - Eindeutigkeit (UNIQUE): Unterbindet doppelte Datensätze unmittelbar auf Ebene des B-Tree-Index.

C. Isolation: Nebenläufigkeit ohne Seiteneffekte

Arbeiten hunderte Client-Verbindungen gleichzeitig auf derselben Datenbank, regelt die Isolationsstufe, ob und wann Änderungen einer laufenden Transaktion T1 für eine parallel laufende Transaktion T2 sichtbar werden.

Die vier klassischen Nebenläufigkeits-Anomalien

  1. Dirty Read: T2 liest Daten, die von T1 geändert, aber noch nicht committet wurden. Rollt T1 zurück, hat T2 mit Daten gearbeitet, die es offiziell nie gab.
  2. Non-Repeatable Read (Fuzzy Read): T1 liest eine Zeile. T2 modifiziert oder löscht diese Zeile und führt ein COMMIT aus. Liest T1 dieselbe Zeile erneut, haben sich die Werte verändert.
  3. Phantom Read: T1 führt eine Bereichsabfrage aus (WHERE status = 'PENDING'). T2 fügt eine neue Zeile ein, die auf diese Bedingung passt, und committet. Liest T1 den Bereich erneut, tauchen plötzlich zusätzliche Zeilen auf.
  4. Serialization Anomaly (Write Skew): Zwei Transaktionen lesen überlappende Datensätze und erfüllen ihre jeweiligen Bedingungen isoliert. Werden beide committet, verletzt ihr gemeinsames Ergebnis eine globale Unternehmensregel.

ANSI-SQL-Isolationsstufen im Vergleich

Isolationsstufe Dirty Read Non-Repeatable Read Phantom Read Serialization Anomaly Standard-Engine
Read Uncommitted Möglich (MySQL) Möglich Möglich Möglich (Wird in PostgreSQL als Read Committed behandelt)
Read Committed Verhindert Möglich Möglich Möglich PostgreSQL & MariaDB Standard
Repeatable Read Verhindert Verhindert Verhindert (PostgreSQL) Möglich (Write Skew) MySQL InnoDB Standard
Serializable Verhindert Verhindert Verhindert Verhindert Auf Anforderung

Snapshot Isolation in PostgreSQL

In PostgreSQL wird die Isolationsstufe REPEATABLE READ mittels Snapshot Isolation implementiert. Dadurch werden auch Phantom Reads zuverlässig verhindert. Echtes Serializable verwendet die sogenannte Serializable Snapshot Isolation (SSI), die Lese-Schreib-Konfliktgraphen überwacht und verdächtige Transaktionen abbricht, bevor es zu Inkonsistenzen kommen kann.

D. Dauerhaftigkeit (Durability): Überleben von Systemabstürzen

Dauerhaftigkeit garantiert: Sobald der Datenbankserver der Client-Anwendung über das Netzwerk ein erfolgreiches COMMIT bestätigt hat, sind die Daten unverlierbar auf nichtflüchtigem Speicher gesichert. Weder ein Kernel-Panic noch ein plötzlicher Stromausfall können die Daten vernichten.

Das Problem wahlfreier Festplattenzugriffe & Write-Ahead Logging (WAL)

Müsste die Datenbank bei jedem Commit sämtliche betroffenen 8 KiB- oder 16 KiB-Seiten auf der Festplatte aktualisieren (Tabellen-Heap, Primärschlüsselindex, Sekundärindizes), würden unzählige wahlfreie Schreibzugriffe (Random I/O) den Datendurchsatz auf wenige Transaktionen pro Sekunde einbrechen lassen.

Moderne Datenbanksysteme nutzen stattdessen das Write-Ahead Logging (WAL):

%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
    C_TX["1. Client sendet COMMIT"]
    WAL_BUF["2. WAL-Record in flüchtigen<br/>WAL-Puffer schreiben"]
    FSYNC["3. Kernel ruft fsync() auf<br/>Flusht Puffer auf NVMe"]
    NVME["4. NVMe bestätigt Speicherung<br/>Sicher im Flash"]
    ACK["5. Engine meldet 'COMMIT OK'<br/>an Client-Anwendung"]
    BG_CHK["6. Checkpointer-Prozess<br/>Schreibt dirty Pages"]

    C_TX --> WAL_BUF
    WAL_BUF --> FSYNC
    FSYNC --> NVME
    NVME --> ACK
    ACK -.-> BG_CHK
  1. Wird ein Datensatz verändert, schreibt die Datenbank ein kompaktes binäres Delta-Protokoll sequenziell in den flüchtigen WAL-Puffer im RAM.
  2. Bei COMMIT stößt die Engine den Kernel-Systemaufruf fsync() an. Dadurch werden alle ausstehenden WAL-Bytes garantiert aus dem Page-Cache des Betriebssystems auf die NVMe geschrieben.
  3. Erst wenn der Speichercontroller den Schreibvorgang bestätigt, sendet das RDBMS die Erfolgsmeldung COMMIT OK an den Client.
  4. Die eigentlichen Datenseiten im RAM (shared_buffers) werden erst später asynchron durch den Hintergrundprozess (Checkpointer) auf die Festplatte geschrieben. Fällt der Strom aus, liest die Engine beim Neustart das WAL ab dem letzten Checkpoint und stellt alle bestätigten Transaktionen deterministisch wieder her (REDO-Log).

3. Hands-on-Labor: Transaktionen & Savepoints in der Praxis

Führe diese Befehle in einer psql-Sitzung aus, um Transaktionsgrenzen und Savepoints praktisch nachzuvollziehen:

-- Datei: /opt/db-ops/transaction_mechanics_lab.sql

-- 1. Test-Tabelle anlegen
DROP TABLE IF EXISTS accounts CASCADE;
CREATE TABLE accounts (
    account_id INT PRIMARY KEY,
    owner_name VARCHAR(100) NOT NULL,
    balance_cents BIGINT NOT NULL CHECK (balance_cents >= 0)
);

INSERT INTO accounts (account_id, owner_name, balance_cents)
VALUES 
    (1, 'Alice Smith', 100000),
    (2, 'Bob Jones', 50000);

-- 2. Demonstration von Savepoints und partiellem Rollback
BEGIN;

UPDATE accounts SET balance_cents = balance_cents - 20000 WHERE account_id = 1;
UPDATE accounts SET balance_cents = balance_cents + 20000 WHERE account_id = 2;

-- Zwischenzustand sichern
SAVEPOINT transfer_one;

-- Fehlerhafte Operation ausführen, die den CHECK-Constraint verletzt
UPDATE accounts SET balance_cents = balance_cents - 200000 WHERE account_id = 1;
-- Schlägt fehl: ERROR: new row for relation "accounts" violates check constraint

-- Nur bis zum Savepoint zurückrollen (die erste Überweisung bleibt erhalten!)
ROLLBACK TO SAVEPOINT transfer_one;

-- Transaktion erfolgreich abschließen
COMMIT;

-- Endstände überprüfen (Alice: 80000, Bob: 70000)
SELECT account_id, owner_name, balance_cents FROM accounts ORDER BY account_id;

4. Architektonische Kern-Erkenntnisse

%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
    ACID["ACID-Kernarchitektur"]
    A_NODE["Atomarität<br/>WAL & MVCC xmin/xmax"]
    C_NODE["Konsistenz<br/>Schema-Constraints"]
    I_NODE["Isolation<br/>Snapshot MVCC & Zeilensperren"]
    D_NODE["Dauerhaftigkeit<br/>fsync() auf WAL vor Commit"]

    ACID --> A_NODE
    A_NODE --> C_NODE
    C_NODE --> I_NODE
    I_NODE --> D_NODE
  • Physische Datenunabhängigkeit: Das relationale Modell trennt die Abfragelogik vollständig von der physischen Speicherstruktur. Abfragen beschreiben, welche Daten benötigt werden; der Optimizer bestimmt, wie darauf zugegriffen wird.
  • WAL sichert hohen Durchsatz: Sequenzielle Schreibzugriffe auf ein lineares Logfile ermöglichen dauerhafte Transaktionen ohne Blockaden durch langsame wahlfreie Schreibzugriffe auf Datenseiten.
  • MVCC eliminiert Lesesperren: Leser blockieren keine Schreiber und Schreiber blockieren keine Leser. Dies wird erreicht, indem mehrere Versions-Snapshots jedes Datensatzes parallel im Speicher vorgehalten werden.