Zusammenfassung

MVCC (Multiversion Concurrency Control) ist ein Verfahren zur Nebenlaeufigkeitskontrolle, bei dem das DBMS statt Datensaetze direkt zu ueberschreiben mehrere Versionen jedes Datenobjekts vorhaelt. Jede Transaktion arbeitet auf einem konsistenten Snapshot der Datenbank zum Startzeitpunkt, wodurch sich Leser und Schreiber niemals gegenseitig blockieren. MVCC ist die Grundlage von Snapshot Isolation und wird von PostgreSQL, Oracle und praktisch allen modernen OLTP-Systemen eingesetzt.

Kernkonzepte

Grundidee MVCC

Statt Datensaetze direkt zu aendern legt das DBMS bei jedem Write eine neue Version des Datenobjekts an. Jedes logische Objekt existiert also physisch in mehreren Versionen gleichzeitig. Ein Lesen greift immer auf die Version zu, die zu Beginn der eigenen Transaktion gueltig war. Damit blockieren sich Leser und Schreiber nie gegenseitig.

Nie ueberschreiben, immer eine neue Version anlegen und lesen aus dem eigenen Snapshot.

Snapshot Isolation

Snapshot Isolation ist die Isolationsstufe, die MVCC praktisch umsetzt. Zu Beginn einer Transaktion bekommt diese einen logischen Zeitstempel, ihren Snapshot. Alle Lesevorgaenge sehen den Datenbankzustand exakt so, wie er zu diesem Zeitstempel committed war. Snapshot Isolation ist NICHT identisch zu Serializable, das write-skew Problem kann noch auftreten.

Snapshot = konsistente Sicht zum Startzeitpunkt der Transaktion.

Versionen und Zeitstempel

Jede physische Version einer Zeile bekommt zwei Zeitstempel: begin-ts markiert, ab wann sie sichtbar wird, end-ts markiert, ab wann sie durch eine neuere Version abgeloest ist. Eine Transaktion T mit Zeitstempel ts sieht genau die Version, fuer die gilt begin-ts <= ts und (end-ts unbekannt oder end-ts > ts).

begin-ts, end-ts, value plus Tx-Status-Tabelle sind die Datenstrukturen von MVCC.

Kein Blockieren bei Reads

Der praktische Kernvorteil von MVCC gegenueber 2PL: Lesetransaktionen brauchen keine Sperre. Auch waehrend ein Schreiber eine Zeile modifiziert, sehen andere Transaktionen ungestoert die alte Version. In OLTP-Systemen und bei Reporting-Queries neben laufendem Tagesgeschaeft ist das der entscheidende Durchsatz-Vorteil.

Reads gehen nie in eine Warteschlange, Writes ebenfalls nicht wegen Reads.

MVCC in Postgres und Oracle

Postgres implementiert MVCC direkt in den Heap-Tuples: jede Zeile hat xmin und xmax als versteckte Systemspalten. Updates erzeugen physisch eine neue Zeile, alte Zeilen werden spaeter durch VACUUM aufgeraeumt. Oracle nutzt stattdessen Undo-Segmente: alte Werte landen im Rollback-Segment, aus dem Leser bei Bedarf die passende alte Version rekonstruieren.

Postgres speichert Versionen im Heap, Oracle rekonstruiert sie aus Undo-Segmenten.

Auswirkungen im DBMS

MVCC ist mehr als ein Sperr-Protokoll und wirkt sich auf mehrere Komponenten aus: Concurrency Control Protocol, Version Storage, Garbage Collection, Index Management und Deletes (loeschen bedeutet eine Version mit end-ts markieren, nicht physisch entfernen). Ein Umstieg auf MVCC kann nicht rueckwirkend gemacht werden.

MVCC beruehrt Concurrency, Storage, GC, Index und Deletes gleichermassen.

Abgrenzung zu 2PL

Beim Two-Phase-Locking fordern Transaktionen S- und X-Sperren an. Sperren sind pessimistisch: sie verhindern Konflikte durch Blockieren, koennen aber zu Deadlocks fuehren. MVCC ist demgegenueber optimistisch fuer Reads: statt zu sperren wird eine neue Version angelegt. Write-Write-Konflikte muessen aber weiterhin erkannt werden.

2PL sperrt, MVCC vervielfaeltigt. Reads sperrfrei, Writes bleiben serialisiert.

Wichtige Details

  • MVCC = Multiversion Concurrency Control: mehrere physische Versionen pro logischem Datenobjekt.
  • Beim Write wird immer eine neue Version angelegt, die alte Version bekommt einen end-ts und bleibt zunaechst erhalten.
  • Beim Read wird die Version zurueckgegeben, die zum Startzeitpunkt der eigenen Transaktion gueltig war (Snapshot).
  • Zentraler Merksatz: Writers do not block readers, readers do not block writers.
  • Datenstruktur je Version: begin-ts, end-ts, value. Zusaetzlich Tx-Status-Tabelle: txnid, timestamp, status (Active/Committed/Aborted).
  • MVCC ist die Grundlage von Snapshot Isolation, verhindert Dirty Read, Nonrepeatable Read und (weitgehend) Phantom-Probleme.
  • MVCC wirkt sich auf: Concurrency Control, Version Storage, Garbage Collection, Index Management und Deletes aus.
  • Postgres implementiert MVCC direkt im Tuple-Header (xmin/xmax), Oracle nutzt Undo-Segmente.
  • Nachteil: Speicherverbrauch steigt durch alte Versionen, deshalb ist Garbage Collection (VACUUM in Postgres) noetig.
  • MVCC allein garantiert NICHT vollstaendige Serialisierbarkeit (write-skew moeglich), dafuer braucht es SSI.

Beispiele

MVCC Grundablauf mit Versionstabelle

Klassisches Beispiel aus der Vorlesung: T1 liest A waehrend T2 A parallel aendert. Beide blockieren sich nicht.

Zustand: A0 (begin-ts=0, end-ts=inf, value=123)

Historie:
T1: BEGIN (ts=1)
T1: R(A) -> liest A0 = 123
T2: BEGIN (ts=2)
T2: W(A) -> DBMS erzeugt neue Version A1 (begin-ts=2, value=456)
              alte Version A0 bekommt end-ts=2
T1: R(A) -> liest weiterhin A0 = 123 (Snapshot bei ts=1)
T1: COMMIT
T2: COMMIT

Ergebnis Datenbanktabelle:
A0: begin-ts=0, end-ts=2, value=123
A1: begin-ts=2, end-ts=-, value=456

=> T1 blockiert nicht, sieht konsistenten Snapshot

Bank-Ueberweisung ohne Blockieren durch Reporting

T1 fuehrt Ueberweisung durch, T2 macht parallel Bilanzsumme. Bei 2PL wuerde T2 warten, mit MVCC liest T2 einen konsistenten Snapshot.

T1 (Ueberweisung 50 von A nach B)   T2 (Reporting: Sum(A)+Sum(B))
BEGIN ts=10                          BEGIN ts=11
read(A) -> 1000
A := A - 50
write(A) -> neue Version A_v11=950
                                     read(A) -> sieht alte Version=1000
                                     read(B) -> sieht alte Version=500
read(B) -> 500                       Summe=1500 (konsistent zum Zeitpunkt ts=11)
B := B + 50                          COMMIT
write(B) -> neue Version B_v12=550
COMMIT

=> Keine Sperren, keine Wartezeit, T2 sieht konsistenten Zustand vor der Ueberweisung.

Verhinderung Nonrepeatable Read durch Snapshot

Unter 2PL waere in Read Committed ein Nonrepeatable Read moeglich. Mit MVCC/Snapshot Isolation wird dies verhindert.

T1 (Kontostand lesen)          T2 (Update)
BEGIN (Snapshot bei ts=5)
SELECT guthaben FROM Konten
WHERE iban=4711 -> 1000
                               BEGIN
                               UPDATE Konten SET guthaben=guthaben+100
                               WHERE iban=4711
                               COMMIT (neue Version bei ts=8)
SELECT guthaben FROM Konten
WHERE iban=4711 -> immer noch 1000
(liest weiter die Version, die bei ts=5 gueltig war)
COMMIT

=> Repeatable Read wird durch MVCC automatisch erreicht.

Postgres/Oracle Praxis

Anschauliches Verhalten in konkreten DBMS. In Postgres ist Read Committed Default und funktioniert komplett ueber MVCC.

Postgres Session 1:               Postgres Session 2:
BEGIN;
SELECT balance FROM konto
  WHERE id=1;  -- 100
                                  BEGIN;
                                  UPDATE konto SET balance=200
                                    WHERE id=1;
                                  -- kein Blockieren fuer Leser
SELECT balance FROM konto
  WHERE id=1;  -- 100 (Session 1 wartet NICHT)
                                  COMMIT;
SELECT balance FROM konto
  WHERE id=1;  -- unter READ COMMITTED: 200
                -- unter REPEATABLE READ: 100
COMMIT;

Grafik: MVCC Ablauf

Zeitachse T1 und T2 T1 (ts=1) T2 (ts=2) BEGIN R(A)=123 R(A)=123 COMMIT BEGIN W(A)=456 COMMIT Datenbanktabelle begin-ts end-ts value 0 2 123 (A0) 2 - 456 (A1) Tx-Status txnid ts status T1 1 Committed T2 2 Committed liest A0 erzeugt A1 Writers do not block readers Readers do not block writers Sichtbarkeitsregel: Version V sichtbar fuer Transaktion T mit Zeitstempel ts, wenn gilt: V.begin-ts <= ts UND (V.end-ts ist leer ODER V.end-ts > ts) Legende: Reader (T1) Writer (T2) alte Version aktuelle Version T1 mit ts=1 sieht A0. T2 legt A1 an. T1 sieht auch nach W(A) durch T2 weiterhin A0.

FAQ - Haeufige Fragen

Was ist der zentrale Unterschied zwischen MVCC und 2PL?
2PL nutzt Sperren, Leser koennen Schreiber blockieren und umgekehrt. MVCC haelt mehrere Versionen jedes Datensatzes vor. Leser bekommen die Version, die zu Beginn ihrer Transaktion gueltig war, Schreiber legen eine neue Version an. Damit blockieren sich Reads und Writes nicht gegenseitig.
Was passiert bei einem Rollback unter MVCC?
Die neu erzeugte Version wird einfach als ungueltig markiert bzw. spaeter vom Garbage Collector entfernt. Die alte Version bleibt sichtbar. Kein aufwaendiges Undo der bestehenden Zeilen ist noetig.
Was ist Snapshot Isolation?
Snapshot Isolation ist die Isolationsstufe, die auf MVCC basiert. Jede Transaktion arbeitet auf einem konsistenten Snapshot der Datenbank zum Startzeitpunkt. Sie sieht nur Aenderungen, die zu diesem Zeitpunkt bereits committed waren, plus die eigenen Aenderungen.
Wie werden alte Versionen wieder aus der Datenbank entfernt?
Ueber Garbage Collection. Sobald keine aktive Transaktion mehr eine bestimmte alte Version braucht (also alle laufenden TAs sind juenger als end-ts der Version), kann sie physisch geloescht werden. In Postgres macht das der VACUUM-Prozess.
Verhindert MVCC alle vier Concurrency-Probleme?
MVCC verhindert Dirty Reads, Nonrepeatable Reads und Lost Updates zuverlaessig. Klassische Phantoms sind ebenfalls weitgehend eliminiert. Es gibt jedoch das write-skew Problem, das reine Snapshot Isolation nicht abfaengt. Dafuer braucht es Serializable Snapshot Isolation.
Warum wirkt sich MVCC auf mehr als nur das Concurrency-Protokoll aus?
Weil neue Versionen gespeichert werden muessen (Version Storage), alte Versionen aufgeraeumt werden muessen (Garbage Collection), Indizes mehrere Versionen adressieren muessen (Index Management) und auch Deletes eine spezielle Behandlung brauchen (logisches Loeschen ueber end-ts).
Welche Metadaten haengen an einer Version?
Jede Version einer Zeile bekommt einen begin-ts (ab wann sichtbar), einen end-ts (bis wann gueltig, - bedeutet aktuell) und den value. Ergaenzend gibt es eine Transaction-Status-Tabelle mit txnid, timestamp und status (Active, Committed, Aborted).
Welche DBMS setzen MVCC ein?
PostgreSQL, Oracle, MySQL InnoDB, SAP HANA, SQL Server (ab optionalem Snapshot Isolation Mode), CockroachDB und praktisch alle modernen verteilten SQL-Systeme. MVCC ist heute der De-facto-Standard fuer OLTP-Systeme.

Pruefungsfragen

0 von 12 Fragen beantwortet 0%