🕰️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 ← →
| t | Sitzung 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.
| Level | Dirty Read | Nicht wiederholbares Lesen | Phantome | Wie InnoDB es umsetzt |
|---|---|---|---|---|
| READ UNCOMMITTED | möglich | möglich | möglich | liest die neueste Version, auch unbestätigt |
| READ COMMITTED | – | möglich | möglich | neuer Read View pro Anweisung; nur Record-Locks (kaum Gap-Locks) |
| REPEATABLE READ (Standard) | – | – | bei konsistentem Lesen nicht; Next-Key-Locks beim sperrenden Lesen | ein 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 |