der SQL-Standard fuer parallele Transaktionen im Detail
Isolation Levels legen fest, wie viel eine Transaktion von parallel laufenden, noch nicht abgeschlossenen Transaktionen sehen darf. Der SQL-Standard definiert vier Stufen von Read Uncommitted bis Serializable, jede mit einem anderen Kompromiss zwischen Korrektheit und Durchsatz, und jede grosse Datenbank waehlt dabei ihren eigenen Default.
Inhaltsverzeichnis
- 1. Warum Isolation Levels existieren
- 2. Der SQL-Standard: vier Isolation Levels im Ueberblick
- 3. Read Uncommitted: die schwaechste Stufe
- 4. Read Committed: der Praxis-Standard
- 5. Repeatable Read: stabile Sicht innerhalb der Transaktion
- 6. Serializable: die staerkste Isolation
- 7. Default Isolation Level je Datenbank
- 8. Isolation Level in der Praxis setzen
- 9. Das richtige Isolation Level fuer den Use-Case waehlen
- 10. Zusammenfassung
- 11. FAQ
1. Warum Isolation Levels existieren
Ein Isolation Level ist der Kompromiss, den eine Datenbank zwischen Korrektheit und Durchsatz eingeht, wenn mehrere Transaktionen gleichzeitig auf dieselben Daten zugreifen. Vollstaendige Isolation, bei der jede Transaktion so ablaeuft, als waere sie allein auf dem System, ist theoretisch am sichersten, aber praktisch am teuersten: Sie erfordert im Zweifel, dass Transaktionen serialisiert oder mit weitreichenden Sperren versehen werden, was Wartezeiten und Deadlocks begueenstigt. Ohne jede Isolation waere der Durchsatz maximal, aber Daten koennten durch parallele Zugriffe unbemerkt korrumpiert werden.
Der SQL-Standard loest dieses Spannungsfeld nicht mit einer einzigen Antwort, sondern mit vier abgestuften Isolation Levels. Jede Stufe erlaubt bestimmte Nebenlaeufigkeitsanomalien nicht mehr, kostet dafuer aber mehr Koordinationsaufwand. Die Wahl des richtigen Isolation Levels ist damit keine rein technische Einstellung, sondern eine bewusste Entscheidung darueber, welche Anomalien fuer den jeweiligen Anwendungsfall tolerierbar sind und welche nicht.
Die folgenden Abschnitte gehen jedes der vier Isolation Levels im Detail durch, zeigen die jeweils verhinderten Anomalien und vergleichen die Default-Einstellungen der wichtigsten relationalen Datenbanken.
2. Der SQL-Standard: vier Isolation Levels im Ueberblick
Der SQL-92-Standard definiert die vier Isolation Levels READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ und SERIALIZABLE anhand von drei Anomalien, die sie jeweils verhindern oder erlauben: Dirty Read, Non-Repeatable Read und Phantom Read. Jede hoehere Stufe schliesst mindestens eine zusaetzliche Anomalie aus, ohne dass die niedrigeren Stufen komplett verschwinden. Diese formale Definition ist wichtig, weil sie festlegt, was ein Isolation Level mindestens leisten muss, nicht wie es implementiert wird.
In der Praxis interpretieren Datenbank-Hersteller den Standard unterschiedlich streng. PostgreSQL etwa verhindert Phantom Reads bereits ab REPEATABLE READ durch seine Snapshot-Isolation, obwohl der Standard das erst fuer SERIALIZABLE vorschreibt. Wer sich beim Design auf ein bestimmtes Isolation Level verlaesst, sollte deshalb immer die Dokumentation der konkreten Datenbank pruefen, nicht nur den generischen Namen des Levels.
3. Read Uncommitted: die schwaechste Stufe
READ UNCOMMITTED ist das schwaechste Isolation Level und erlaubt Dirty Reads: Eine Transaktion darf Daten lesen, die eine andere Transaktion bereits geschrieben, aber noch nicht committet hat. Wird die schreibende Transaktion anschliessend zurueckgerollt, hat die lesende Transaktion mit Werten gearbeitet, die nie tatsaechlich existiert haben. Dieses Level bietet praktisch keinen Schutz vor Nebenlaeufigkeitsproblemen und wird in der Praxis kaum noch aktiv verwendet.
Sinnvoll ist READ UNCOMMITTED fast ausschliesslich fuer Auswertungen, bei denen absolute Praezision unwichtig ist und maximaler Durchsatz Prioritaet hat, etwa grobe Monitoring-Dashboards, die naeherungsweise Zaehlwerte anzeigen. MySQL/InnoDB unterstuetzt dieses Level, verwendet es aber nicht als Default. PostgreSQL akzeptiert READ UNCOMMITTED als Syntax, behandelt es intern jedoch identisch zu READ COMMITTED, weil PostgreSQL grundsaetzlich keine Dirty Reads erlaubt.
4. Read Committed: der Praxis-Standard
READ COMMITTED ist das am weitesten verbreitete Isolation Level und der Default in PostgreSQL, Oracle und SQL Server. Es verhindert Dirty Reads vollstaendig: Eine Transaktion sieht ausschliesslich Daten, die von anderen Transaktionen bereits committet wurden. Innerhalb derselben Transaktion kann sich der gelesene Wert einer Zeile aber trotzdem zwischen zwei SELECT-Anweisungen aendern, wenn eine andere Transaktion dazwischen committet, das ist die Non-Repeatable-Read-Anomalie, die READ COMMITTED explizit noch erlaubt.
Technisch setzen moderne Datenbanken READ COMMITTED meist ueber MVCC um: Jede einzelne Anweisung innerhalb der Transaktion sieht einen frischen Snapshot der zu diesem Zeitpunkt committeten Daten, nicht die gesamte Transaktion einen einzigen Snapshot. Das erklaert, warum zwei aufeinanderfolgende SELECTs in derselben Transaktion unterschiedliche Ergebnisse liefern koennen, obwohl beide jeweils fuer sich konsistent sind. Fuer die meisten Web-Anwendungen mit kurzen Transaktionen ist READ COMMITTED ein guter Kompromiss aus Sicherheit und Performance.
-- Read Committed: Non-Repeatable Read innerhalb einer Transaktion moeglich
-- Session A:
BEGIN;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT price FROM products WHERE product_id = 42; -- liefert 19.99
-- Session B (parallel, committet zwischendurch):
-- UPDATE products SET price = 24.99 WHERE product_id = 42;
-- COMMIT;
-- Session A, gleiche Transaktion, zweite Abfrage:
SELECT price FROM products WHERE product_id = 42; -- liefert jetzt 24.99
COMMIT;
-- Beide Werte sind fuer sich korrekt, aber innerhalb einer Transaktion
-- widerspruechlich, das ist die Non-Repeatable-Read-Anomalie
5. Repeatable Read: stabile Sicht innerhalb der Transaktion
REPEATABLE READ garantiert, dass eine Transaktion dieselbe Zeile innerhalb ihrer gesamten Laufzeit immer mit demselben Wert liest, unabhaengig davon, wie viele andere Transaktionen dazwischen committen. Das verhindert Non-Repeatable Reads vollstaendig. Umgesetzt wird das meist ueber einen einzigen konsistenten Snapshot, der beim Start der Transaktion erstellt wird und fuer die gesamte Transaktion gilt, statt bei jeder Anweisung neu zu snapshotten wie bei READ COMMITTED.
Der SQL-Standard erlaubt bei REPEATABLE READ theoretisch weiterhin Phantom Reads, also neue Zeilen, die durch eine parallele INSERT-Transaktion bei einer wiederholten Bereichsabfrage ploetzlich auftauchen. MySQL/InnoDB, das REPEATABLE READ als Default verwendet, verhindert Phantom Reads in der Praxis jedoch weitgehend durch sogenannte Next-Key-Locks, eine Kombination aus Zeilen- und Luecken-Sperren. PostgreSQL verhindert Phantom Reads bei REPEATABLE READ durch seine Snapshot-Isolation ebenfalls vollstaendig, erkennt aber bei echten Schreibkonflikten eine Serialization Failure und bricht die Transaktion ab, statt sie stillschweigend inkorrekt laufen zu lassen.
-- Repeatable Read: stabiler Snapshot ueber die gesamte Transaktion
-- Session A:
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT balance FROM accounts WHERE account_id = 1; -- liefert 1000.00
-- Session B (parallel, committet zwischendurch):
-- UPDATE accounts SET balance = 1500.00 WHERE account_id = 1;
-- COMMIT;
-- Session A, gleiche Transaktion, zweite Abfrage derselben Zeile:
SELECT balance FROM accounts WHERE account_id = 1; -- liefert weiterhin 1000.00
COMMIT;
-- Der Snapshot vom Transaktionsstart bleibt fuer die gesamte
-- Laufzeit stabil, unabhaengig davon, was parallel committet wird
6. Serializable: die staerkste Isolation
SERIALIZABLE ist das staerkste Isolation Level und garantiert, dass das Ergebnis paralleler Transaktionen immer identisch zu einer moeglichen seriellen, also nacheinander ausgefuehrten Reihenfolge dieser Transaktionen ist. Alle drei Standard-Anomalien, Dirty Read, Non-Repeatable Read und Phantom Read, sind damit ausgeschlossen. Diese Garantie hat ihren Preis: Datenbanken muessen entweder echte Sperren fuer ganze Wertebereiche setzen oder, wie bei modernen MVCC-Systemen ueblich, Schreibkonflikte zur Laufzeit erkennen und eine der beteiligten Transaktionen mit einem Serialization-Failure-Fehler abbrechen.
Dieser Serialization-Failure-Mechanismus bedeutet in der Praxis, dass Anwendungscode bei SERIALIZABLE immer eine Retry-Logik implementieren muss: Eine Transaktion, die aufgrund eines Konflikts abgebrochen wird, sollte automatisch mit einem neuen Versuch wiederholt werden, nicht als endgueltiger Fehler an den Benutzer weitergereicht werden. Ohne diese Retry-Logik fuehrt SERIALIZABLE bei hoher Nebenlaeufigkeit schnell zu sichtbaren Fehlern, obwohl das Level technisch korrekt funktioniert.
-- Serializable: Datenbank erkennt Schreibkonflikte zur Laufzeit
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT SUM(amount) FROM transactions WHERE account_id = 7;
-- Anwendung berechnet neuen Kontostand basierend auf dieser Summe
INSERT INTO transactions (account_id, amount) VALUES (7, -50.00);
COMMIT;
-- Bei einem echten Konflikt mit einer parallelen Transaktion:
-- ERROR: could not serialize access due to read/write dependencies
-- Anwendungscode muss diesen Fehler abfangen und die Transaktion
-- vollstaendig neu starten, nicht nur den letzten Befehl wiederholen
7. Default Isolation Level je Datenbank
Datenbank-Hersteller waehlen ihren Default nicht zufaellig, sondern nach dem in ihrer Community am haeufigsten erwarteten Kompromiss zwischen Sicherheit und Performance. Wer sich auf den Default verlaesst, ohne ihn explizit zu pruefen, kann beim Wechsel der Datenbank-Engine unerwartet andere Isolation-Level-Garantien erhalten.
| Datenbank | Default Isolation Level | Phantom Reads bei Default | Mechanismus |
|---|---|---|---|
| PostgreSQL | READ COMMITTED | Moeglich | MVCC, Snapshot pro Anweisung |
| MySQL / InnoDB | REPEATABLE READ | Weitgehend verhindert | MVCC plus Next-Key-Locks |
| Oracle Database | READ COMMITTED | Moeglich | MVCC mit Undo-Segmenten |
| Microsoft SQL Server | READ COMMITTED | Moeglich | Lock-basiert, optional Snapshot-Modus |
| SQLite | SERIALIZABLE | Ausgeschlossen | Ein Schreiber gleichzeitig (WAL-Modus erlaubt parallele Leser) |
8. Isolation Level in der Praxis setzen
Das Isolation Level wird pro Transaktion oder pro Session mit standardisierter Syntax gesetzt, wobei die genaue Reichweite je Datenbank leicht variiert. Die Anweisung muss vor der ersten datenmodifizierenden Anweisung der Transaktion stehen, ein nachtraeglicher Wechsel innerhalb einer laufenden Transaktion ist bei den meisten Datenbanken nicht erlaubt oder wirkt sich nur auf zukuenftige Anweisungen aus.
-- PostgreSQL und Standard-SQL-Syntax: pro Transaktion
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- ... Anweisungen ...
COMMIT;
-- MySQL: Isolation Level fuer die naechste Transaktion der Session
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
-- ... Anweisungen ...
COMMIT;
-- SQL Server: Snapshot-Isolation als READ-COMMITTED-Alternative aktivieren
ALTER DATABASE MyDatabase SET READ_COMMITTED_SNAPSHOT ON;
-- Aktuelles Isolation Level pruefen (PostgreSQL)
SHOW TRANSACTION ISOLATION LEVEL;
9. Das richtige Isolation Level fuer den Use-Case waehlen
Die Wahl des Isolation Level sollte immer aus den Konsequenzen einer moeglichen Anomalie abgeleitet werden, nicht aus einer pauschalen Vorliebe fuer maximale Sicherheit. Fuer die meisten CRUD-lastigen Web-Anwendungen mit kurzen, unabhaengigen Transaktionen reicht READ COMMITTED vollstaendig aus, weil einzelne Anweisungen ohnehin meist fuer sich konsistent sein muessen und selten mehrere zusammenhaengende Lesevorgaenge innerhalb einer Transaktion kritisch sind.
REPEATABLE READ oder SERIALIZABLE werden dann relevant, wenn eine Transaktion mehrere Lesevorgaenge durchfuehrt und auf deren Konsistenz zueinander angewiesen ist, etwa bei Finanzberichten, Bestandsreservierungen oder komplexen Business-Regeln, die auf mehreren zusammenhaengenden Werten basieren. SERIALIZABLE ist die richtige Wahl, wenn Korrektheit absolute Prioritaet hat und die Anwendung bereit ist, Serialization Failures mit einer Retry-Schleife abzufangen. Fuer alle anderen Faelle ist ein niedrigeres Isolation Level kombiniert mit gezieltem Locking, wie es die Beitraege zu Optimistic und Pessimistic Locking beschreiben, oft die pragmatischere Loesung.
-- Retry-Wrapper fuer Serializable in Pseudocode
-- (angelehnt an gaengige Datenbank-Treiber-APIs)
-- function runWithRetry(work, maxAttempts = 3) {
-- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
-- try {
-- db.execute("BEGIN");
-- db.execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
-- const result = work();
-- db.execute("COMMIT");
-- return result;
-- } catch (error) {
-- db.execute("ROLLBACK");
-- if (error.code === 'SERIALIZATION_FAILURE' && attempt < maxAttempts) {
-- continue; // kompletter Neustart der Transaktion
-- }
-- throw error;
-- }
-- }
-- }
10. Zusammenfassung
Die vier Isolation Levels des SQL-Standards, READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ und SERIALIZABLE, bilden eine Stufenleiter zwischen maximaler Nebenlaeufigkeit und maximaler Korrektheit. Jede Stufe schliesst eine zusaetzliche Anomalie aus: READ COMMITTED verhindert Dirty Reads, REPEATABLE READ zusaetzlich Non-Repeatable Reads, SERIALIZABLE zusaetzlich Phantom Reads und garantiert vollstaendige Serialisierbarkeit.
In der Praxis unterscheiden sich die Defaults der grossen Datenbanken erheblich, PostgreSQL und Oracle setzen auf READ COMMITTED, MySQL/InnoDB auf REPEATABLE READ. Wer eine Anwendung datenbankuebergreifend entwickelt oder migriert, sollte das Isolation Level deshalb immer explizit setzen, statt sich auf implizite Defaults zu verlassen. Die Wahl sollte sich an den tatsaechlichen Konsequenzen einer Anomalie orientieren, nicht an einer pauschalen Praeferenz fuer die staerkste verfuegbare Stufe.
Isolation Levels von Read Committed bis Serializable, das Wichtigste auf einen Blick
Read Uncommitted
Erlaubt Dirty Reads, praktisch kaum genutzt, hoechster theoretischer Durchsatz bei geringster Sicherheit.
Read Committed
Verhindert Dirty Reads, Default in PostgreSQL, Oracle und SQL Server, guter Kompromiss fuer die meisten Anwendungen.
Repeatable Read
Verhindert zusaetzlich Non-Repeatable Reads, Default in MySQL/InnoDB, stabile Sicht ueber die ganze Transaktion.
Serializable
Verhindert alle drei Standard-Anomalien, erfordert Retry-Logik fuer Serialization Failures im Anwendungscode.