🕰️MVCC: Jeder sieht seinen eigenen Stand

Multi-Version Concurrency Control: Leser warten nicht auf Schreiber und umgekehrt. InnoDB hält alte Zeilenversionen im Undo-Log und entscheidet mit einem Read View, welche Version eine Transaktion sehen darf.

🎬Zwei Sitzungen als Zeitleiste

Wähle ein Szenario und das Isolationslevel von Sitzung A. Rechts siehst du die Versionskette, die Read Views und bei jedem SELECT die Sichtbarkeitsprüfung Version für Version.

A liest dreimal denselben Kontostand, B ändert ihn dazwischen und bestätigt. Wechsle das Isolationslevel von A und vergleiche.

Schritt 1 / 10 · Tasten ← →
tSitzung A (REPEATABLE READ)Sitzung B (REPEATABLE READ)
1
BEGIN;
2
SELECT saldo FROM konto WHERE id = 1;
3
BEGIN;
4
UPDATE konto SET saldo = 50 WHERE id = 1;
5
SELECT saldo FROM konto WHERE id = 1;
6
COMMIT;
7
SELECT saldo FROM konto WHERE id = 1;
8
COMMIT;
9
SELECT saldo FROM konto WHERE id = 1;

Versionskette von konto id = 1

neueste Version im Clustered Index, ältere über DB_ROLL_PTR im Undo-Log

saldo = 100DB_TRX_ID = 12 bestätigt
Nächste trx_id: 20 · aktive Schreib-Transaktionen: []
Read View von A
kein Read View
Read View von B
kein Read View

📐Die Sichtbarkeitsregel

sichtbar(version, view):
  if version.trx_id == view.creator_trx_id: return JA      # eigene Änderung
  if version.trx_id <  view.up_limit_id:    return JA      # vor dem Snapshot bestätigt
  if version.trx_id >= view.low_limit_id:   return NEIN    # später gestartet
  if version.trx_id in view.ids:            return NEIN    # damals noch offen
  return JA                                                # damals schon bestätigt

Unsichtbar? → DB_ROLL_PTR folgen und die ältere Version prüfen.
💡 Konsistentes vs. sperrendes Lesen
Ein normales SELECT liest den Snapshot. UPDATE, DELETE, SELECT … FOR UPDATE und LOCK IN SHARE MODE lesen dagegen die neueste bestätigte Version und sperren sie („current read“).
⚠️ innodb_snapshot_isolation
Seit MariaDB 11.6.2 standardmäßig ON (auch im LTS 11.8 und 12.3; in 10.6, 10.11 und 11.4 existiert die Option, ist aber OFF). Will eine REPEATABLE-READ-Transaktion eine Zeile sperren, deren neueste Version für ihren Snapshot unsichtbar ist, gibt es ERROR 1020 Record has changed since last read statt eines stillen „Lost Update“.
✅ Purge und lange Transaktionen
Alte Versionen dürfen erst gelöscht werden, wenn kein Read View sie mehr braucht. Eine stundenlang offene Transaktion lässt das Undo-Log wachsen („History list length“ in SHOW ENGINE INNODB STATUS).

🎚️Isolationslevel im Vergleich

Standard in MariaDB (wie MySQL) ist REPEATABLE READ. Ändern mit SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; bzw. transaction_isolation in der my.cnf.
LevelDirty ReadNicht wiederholbares LesenPhantomeWie InnoDB es umsetzt
READ UNCOMMITTEDmöglichmöglichmöglichliest die neueste Version, auch unbestätigt
READ COMMITTED–möglichmöglichneuer Read View pro Anweisung; nur Record-Locks (kaum Gap-Locks)
REPEATABLE READ (Standard)––bei konsistentem Lesen nicht; Next-Key-Locks beim sperrenden Lesenein Read View pro Transaktion (ab dem ersten Lesen)
SERIALIZABLE–––wie REPEATABLE READ, aber jedes SELECT in einer Transaktion wird zu SELECT … LOCK IN SHARE MODE