add synced notes on IT know how
This commit is contained in:
+384
@@ -0,0 +1,384 @@
|
||||
#datenbank
|
||||
➡️[[#Zusammenfassung]]
|
||||
|
||||
---
|
||||
MVCC („==Multi-Version Concurrency Control==“) ist ein Verfahren, mit dem Datenbanken gleichzeitige Zugriffe (Concurrency) von vielen Benutzern/Programmen steuern, ohne dass sie sich ständig gegenseitig blockieren.
|
||||
|
||||
Ich gehe Schritt für Schritt vor:
|
||||
|
||||
1. Ausgangspunkt: Was ist das Problem überhaupt?
|
||||
2. Grunddefinition von MVCC (für Einsteiger)
|
||||
3. Wie funktioniert das intern grob?
|
||||
4. Abgrenzung zu verwandten Konzepten
|
||||
5. Welche Probleme löst MVCC konkret?
|
||||
6. Welche Herausforderungen/Nachteile bringt MVCC mit sich?
|
||||
7. Praxisnahe Beispiele
|
||||
|
||||
---
|
||||
|
||||
## 1. Ausgangspunkt: Wozu brauche ich so etwas?
|
||||
|
||||
In einer typischen Anwendung greifen viele Nutzer gleichzeitig auf dieselbe Datenbank zu:
|
||||
|
||||
- Nutzer A liest Daten (z.B. Produktliste im Shop)
|
||||
- Nutzer B aktualisiert Daten (z.B. ändert Preise)
|
||||
- Nutzer C führt einen großen Report aus (z.B. tägliche Umsatzauswertung)
|
||||
|
||||
Ziel:
|
||||
Alle sollen gleichzeitig arbeiten können, **ohne Fehler** wie:
|
||||
|
||||
- „Dirty Reads“ (jemand liest halbfertige Änderungen)
|
||||
- Inkonsistente Sicht auf die Daten
|
||||
- Datenverlust, weil gleichzeitige Änderungen sich überschreiben
|
||||
- Dauerhafte Sperren und Deadlocks, die das System verlangsamen oder blockieren
|
||||
|
||||
Dazu gibt es das Konzept der **Transaktionen** (ACID):
|
||||
|
||||
- **A**tomicity: Alles oder nichts.
|
||||
- **C**onsistency: Regeln der Datenbank bleiben erfüllt.
|
||||
- **I**solation: Transaktionen beeinflussen sich möglichst wenig.
|
||||
- **D**urability: Einmal bestätigte Daten gehen nicht verloren.
|
||||
|
||||
Die Isolation ist das Kernfeld, in dem MVCC ins Spiel kommt:
|
||||
Wie sorgt man dafür, dass viele Transaktionen **gleichzeitig** laufen können, ohne sich ständig zu blockieren?
|
||||
|
||||
---
|
||||
|
||||
## 2. Grunddefinition von MVCC (für Einsteiger)
|
||||
|
||||
**MVCC (Multi-Version Concurrency Control)** bedeutet:
|
||||
|
||||
- **Jede Zeile (Row) in einer Tabelle existiert in mehreren Versionen.**
|
||||
- Jede Transaktion sieht die Daten „so, wie sie zu einem bestimmten Zeitpunkt waren“ – sie arbeitet mit einem **Snapshot** (Momentaufnahme).
|
||||
- Wenn jemand etwas **ändert**, wird **nicht** die existierende Zeile überschrieben, sondern eine **neue Version** der Zeile angelegt.
|
||||
- Für jede Transaktion gibt es Regeln, **welche Version** einer Zeile sie sehen darf.
|
||||
|
||||
Anschaulich:
|
||||
|
||||
- Stell dir eine Tabelle als Tabelle in Excel vor.
|
||||
- MVCC macht von einigen Zeilen „Kopien“, wenn sie geändert werden.
|
||||
- Du (deine Transaktion) siehst eine konsistente Version des Tabellenblatts zu dem Zeitpunkt, als du angefangen hast – auch wenn andere währenddessen schon neue Versionen erzeugt haben.
|
||||
|
||||
---
|
||||
|
||||
## 3. Wie funktioniert MVCC grob intern?
|
||||
|
||||
Vereinfachtes Modell (z.B. ähnlich wie in PostgreSQL/InnoDB):
|
||||
|
||||
### 3.1. Versionen von Zeilen
|
||||
|
||||
Statt einer Zeile gibt es:
|
||||
|
||||
- Version 1: erstellt von Transaktion T1
|
||||
- Version 2: später erstellt von Transaktion T2 (z.B. nach einem UPDATE)
|
||||
- Version 3: später erstellt von T3, usw.
|
||||
|
||||
Jede Version hat Metadaten, z.B.:
|
||||
|
||||
- „ab Transaktion X gültig“
|
||||
- „bis Transaktion Y gültig“
|
||||
(oder „gelöscht ab Transaktion Y“)
|
||||
|
||||
### 3.2. Was sieht eine Transaktion?
|
||||
|
||||
Wenn eine neue Transaktion T liest:
|
||||
|
||||
- Sie merkt sich einen „Zeitpunkt“ (z.B. eine Transaktions-ID oder Timestamp).
|
||||
- Beim Lesen prüft sie pro Zeile:
|
||||
|
||||
- Wurde diese Version **vor** meinem Start erzeugt und war zu dem Zeitpunkt schon committed?
|
||||
- Wurde sie danach erzeugt? Dann darf ich sie nicht sehen.
|
||||
- Ist sie bereits gelöscht oder von einer laufenden Transaktion verändert, die noch nicht committed ist? Dann gilt sie für mich ggf. als nicht existent.
|
||||
|
||||
Das Ergebnis:
|
||||
Du bekommst einen **konsistenten Snapshot** der Daten – so, als ob alle Änderungen nach deinem Start noch nicht existieren.
|
||||
|
||||
### 3.3. Schreiben mit MVCC
|
||||
|
||||
Beim **UPDATE** einer Zeile:
|
||||
|
||||
1. Alte Version bleibt im Speicher (zunächst noch sichtbar für alte Transaktionen).
|
||||
2. Neue Version wird erzeugt, mit „gültig ab Transaktion T“.
|
||||
3. Für neu startende Transaktionen ist **nach Commit** nur noch die neue Version relevant.
|
||||
|
||||
Beim **DELETE**:
|
||||
|
||||
- Die Zeile bekommt sozusagen ein „Todes-Zeitstempel“ (gültig bis T).
|
||||
- Alte Transaktionen sehen sie noch, neue nicht mehr.
|
||||
|
||||
### 3.4. Aufräumen („Vacuum“, Garbage Collection)
|
||||
|
||||
Alte Versionen, die **keine** Transaktion mehr sehen kann, sind Müll:
|
||||
|
||||
- Es gibt Prozess(e), die diese alten Versionen von Zeit zu Zeit **physisch entfernen**.
|
||||
- Beispiel-Begriff: in PostgreSQL „VACUUM“.
|
||||
|
||||
---
|
||||
|
||||
## 4. Abgrenzung zu verwandten Konzepten
|
||||
|
||||
### 4.1. MVCC vs. „klassische“ Sperren (Locking)
|
||||
|
||||
Früher (oder in einfachen Systemen):
|
||||
|
||||
- Jede Transaktion, die liest oder schreibt, setzt **Sperren** (Locks) auf Zeilen oder ganze Tabellen.
|
||||
- Wenn du eine Zeile liest, kann ein strenges System diese Zeile sperren, sodass andere sie nicht ändern dürfen, bis du fertig bist.
|
||||
- Das kann zu Blockaden und Deadlocks führen.
|
||||
|
||||
**MVCC-Ansatz:**
|
||||
|
||||
- Leser blockieren Schreiber **nicht** (oder nur minimal).
|
||||
- Schreiber blockieren Leser **nicht** (solange es nur um das Lesen bereits existierender, „alter“ Versionen geht).
|
||||
- Es gibt zwar weiterhin Sperren, aber sie sind oft nur für Konfliktfälle relevant (z.B. zwei Transaktionen, die **dieselbe** Zeile gleichzeitig ändern wollen).
|
||||
|
||||
MVCC ersetzt also nicht jede Form von Locking, sondern **reduziert** deren Notwendigkeit für Lesezugriffe stark.
|
||||
|
||||
### 4.2. MVCC vs. Snapshot Isolation
|
||||
|
||||
- **MVCC** ist ein **Mechanismus**: mehrere Versionen von Zeilen, Snapshots, Sichtbarkeitsregeln.
|
||||
- **Snapshot Isolation** ist eine **Isolationsebene** (ein bestimmter Garantiesatz für Transaktionen), die **auf MVCC aufbaut**.
|
||||
|
||||
Viele Systeme verwenden MVCC, um Snapshot Isolation umzusetzen:
|
||||
|
||||
- Jede Transaktion sieht den Datenbestand so, wie er beim Start (oder beim Start des Statements) war.
|
||||
- Aber: Snapshot Isolation ist oft **nicht vollständig serialisierbar** (siehe Write Skew Problem weiter unten).
|
||||
|
||||
Kurz:
|
||||
MVCC = Wie die Datenbank Versionen verwaltet.
|
||||
Snapshot Isolation = Welche Sicht und Garantien Transaktionen bekommen.
|
||||
|
||||
### 4.3. MVCC vs. Optimistic Concurrency Control (OCC)
|
||||
|
||||
- **Optimistic Concurrency Control** geht davon aus: Konflikte sind selten, man lässt Transaktionen frei operieren und prüft erst beim Commit, ob es Konflikte gab.
|
||||
- Viele MVCC-Systeme verwenden **Elemente von OCC**: Sie lassen Transaktionen auf einem Snapshot arbeiten und prüfen erst beim Commit, ob sie z.B. eine Zeile verändert haben, die inzwischen jemand anders schon geändert hat.
|
||||
|
||||
MVCC ist also kein direkter Gegensatz zu OCC, sondern eher eine Technik, mit der man OCC effizient implementieren kann.
|
||||
|
||||
---
|
||||
|
||||
## 5. Welche Probleme werden durch MVCC gelöst?
|
||||
|
||||
### 5.1. Leser blockieren Schreiber nicht (und umgekehrt)
|
||||
|
||||
**Problem ohne MVCC:**
|
||||
Großer Report läuft lange und sperrt viele Zeilen oder Tabellen. Schreibende Transaktionen können nicht mehr weiterarbeiten.
|
||||
|
||||
**Mit MVCC:**
|
||||
|
||||
- Der Report bekommt einen Snapshot.
|
||||
- Während der Report läuft:
|
||||
- Andere Transaktionen können neue Versionen schreiben.
|
||||
- Der Report liest weiterhin die alten Versionen, die für ihn gültig sind.
|
||||
- Ergebnis: lange lesende Transaktionen blockieren das System weit weniger.
|
||||
|
||||
**Praxisbeispiel:**
|
||||
|
||||
- Ein Online-Shop:
|
||||
- Ein Reporting-Job zählt alle Bestellungen des letzten Monats.
|
||||
- Gleichzeitig legen Kunden neue Bestellungen an.
|
||||
- Mit MVCC:
|
||||
- Reporting-Job sieht einen stabilen Stand („Stand 10:00 Uhr“).
|
||||
- Kunden können weiter bestellen; diese Bestellungen erscheinen evtl. nicht im aktuellen Report, aber im nächsten.
|
||||
|
||||
### 5.2. Konsistente Lese-Sichten
|
||||
|
||||
Lesende Transaktionen sehen eine **konsistente Momentaufnahme**, nicht einen Mix aus „halb alt, halb neu“.
|
||||
|
||||
Beispiel:
|
||||
|
||||
- Du willst sicherstellen, dass Summe aller Kontosalden = 0 (Bilanz).
|
||||
- Ohne MVCC könntest du beim Lesen ein Konto schon nach der neuen Buchung sehen, ein anderes aber noch vor der Buchung – Ergebnis: inkonsistente Summe.
|
||||
- Mit MVCC liest du alles so, wie es zu deinem Startzeitpunkt war.
|
||||
|
||||
### 5.3. Hohe Skalierbarkeit für viele Leser
|
||||
|
||||
MVCC ist besonders stark in Systemen mit:
|
||||
|
||||
- hohem Leseanteil (Reports, Dashboards, APIs)
|
||||
- vielen parallelen Nutzern
|
||||
|
||||
Weil Leser nicht permanent Schreiblocks blockieren, kann das System mehr parallele Anfragen verarbeiten.
|
||||
|
||||
### 5.4. Reduzierte Deadlocks
|
||||
|
||||
Deadlocks entstehen oft, wenn zwei Transaktionen sich gegenseitig Sperren wegnehmen wollen.
|
||||
Da MVCC Leser weitgehend von Locks entkoppelt, reduziert sich die Deadlock-Wahrscheinlichkeit, insbesondere bei reinen Lesezugriffen.
|
||||
|
||||
---
|
||||
|
||||
## 6. Welche Herausforderungen und Nachteile hat MVCC?
|
||||
|
||||
### 6.1. Speicher-Overhead durch viele Versionen
|
||||
|
||||
Da alte Versionen zunächst liegen bleiben, kann es passieren:
|
||||
|
||||
- Tabellen werden „aufgebläht“ (Bloat).
|
||||
- Disk-Verbrauch steigt, Indexe werden größer, Performance sinkt.
|
||||
|
||||
Darum braucht man:
|
||||
|
||||
- Mechanismen zur Bereinigung (VACUUM, Garbage Collection)
|
||||
- Tuning (z.B. wie aggressiv wird gereinigt?)
|
||||
|
||||
**Praxisproblem:**
|
||||
Ein System mit dauernd vielen Updates/Deletes, aber schlecht eingestelltem Vacuum, kann plötzlich deutlich langsamer werden, weil die Tabellen intern riesig sind.
|
||||
|
||||
### 6.2. Lang laufende Transaktionen halten alte Versionen fest
|
||||
|
||||
Wenn eine Transaktion sehr lange offen bleibt (z.B. ein Report, der 2 Stunden läuft):
|
||||
|
||||
- Alle Versionen, die **für diese Transaktion sichtbar sein könnten**, müssen erhalten bleiben.
|
||||
- Die Datenbank kann diese Versionen nicht löschen, weil sie noch gebraucht werden.
|
||||
- Folge: Bloat, mehr Speicherverbrauch, mehr I/O, langsamere Zugriffe.
|
||||
|
||||
Praxisnahe Konsequenz:
|
||||
|
||||
- Man versucht in produktiven Systemen:
|
||||
- Lange Transaktionen zu vermeiden oder
|
||||
- Sie auf Replikas/Read-Only-Kopien auszulagern.
|
||||
|
||||
### 6.3. Anomalien unter Snapshot Isolation (Write Skew)
|
||||
|
||||
Snapshot Isolation (häufig via MVCC umgesetzt) ist oft **nicht vollständig serialisierbar**.
|
||||
|
||||
Beispiel (vereinfacht):
|
||||
|
||||
- Zwei Ärzte müssen gleichzeitig im Krankenhaus Dienst haben.
|
||||
- Regel: Es dürfen nie **beide** Ärzte gleichzeitig „Off-Duty“ sein.
|
||||
- Tabelle `dienstplan` mit Einträgen pro Arzt.
|
||||
|
||||
Transaktion T1:
|
||||
|
||||
```sql
|
||||
BEGIN;
|
||||
SELECT COUNT(*) FROM dienstplan WHERE on_duty = TRUE;
|
||||
-- Ergebnis: 2 (Arzt A und B sind im Dienst)
|
||||
|
||||
-- T1 setzt Arzt A auf off-duty
|
||||
UPDATE dienstplan SET on_duty = FALSE WHERE arzt = 'A';
|
||||
COMMIT;
|
||||
```
|
||||
|
||||
Transaktion T2 (parallel, mit eigenem Snapshot):
|
||||
|
||||
```sql
|
||||
BEGIN;
|
||||
SELECT COUNT(*) FROM dienstplan WHERE on_duty = TRUE;
|
||||
-- Ergebnis: 2 (sieht noch alten Stand, beide on duty)
|
||||
|
||||
-- T2 setzt Arzt B auf off-duty
|
||||
UPDATE dienstplan SET on_duty = FALSE WHERE arzt = 'B';
|
||||
COMMIT;
|
||||
```
|
||||
|
||||
Beide Transaktionen sehen **denselben alten Stand** („2 Ärzte im Dienst“).
|
||||
Beide halten es für zulässig, je einen Arzt auf off-duty zu setzen.
|
||||
Ergebnis nach beiden Commits: **0 Ärzte im Dienst**, Regel verletzt.
|
||||
|
||||
Das ist ein typischer **Write Skew** – möglich unter Snapshot Isolation, obwohl MVCC sauber arbeitet.
|
||||
|
||||
Lösung:
|
||||
|
||||
- Strengere Isolationsebene: **SERIALIZABLE** (die DB verhindert durch zusätzliche Checks solche Fälle),
|
||||
oder
|
||||
- Explizite Sperren / zusätzliche Constraints durch den Entwickler.
|
||||
|
||||
### 6.4. Komplexere Implementierung und Tuning
|
||||
|
||||
MVCC ist intern relativ komplex:
|
||||
|
||||
- Verwaltung von Versionen
|
||||
- Sichtbarkeitslogik
|
||||
- Garbage Collection
|
||||
- Umgang mit Hot-Spot-Tabellen (sehr häufig aktualisierte Zeilen)
|
||||
|
||||
Für Administratoren/Entwickler bedeutet das:
|
||||
|
||||
- Man muss verstehen, wie die eigene DB MVCC implementiert (PostgreSQL, MySQL InnoDB, Oracle, SQL Server etc. machen es leicht unterschiedlich).
|
||||
- Man muss Parameter fürs Aufräumen und für Isolationsebenen sinnvoll setzen.
|
||||
|
||||
---
|
||||
|
||||
## 7. Praxisnahe Beispiele
|
||||
|
||||
### Beispiel 1: Webshop – Produktpreise ändern
|
||||
|
||||
Situation:
|
||||
|
||||
- Tabelle `produkte` mit Spalte `preis`.
|
||||
- Viele Nutzer sehen gleichzeitig das Produkt im Shop.
|
||||
- Ein Admin ändert den Preis.
|
||||
|
||||
Ohne MVCC (vereinfachte, pessimistische Sperrung):
|
||||
|
||||
- Admin setzt Lock auf Zeile/Produkt.
|
||||
- Solange Admin noch nicht committed hat:
|
||||
- Kunden könnten blockiert werden oder
|
||||
- sie sehen unklare Zwischenzustände.
|
||||
|
||||
Mit MVCC:
|
||||
|
||||
- Admin-Transaktion erzeugt eine **neue Version** der Produktzeile mit neuem Preis.
|
||||
- Kunden, die vor dem Commit lesen:
|
||||
- sehen die **alte Version** (alten Preis).
|
||||
- Kunden, die nach dem Commit lesen:
|
||||
- sehen die **neue Version** (neuen Preis).
|
||||
- Es gibt keine Lese-Blockade während der Preisänderung.
|
||||
|
||||
### Beispiel 2: Reporting vs. Online-Transaktionen
|
||||
|
||||
- Ein Finance-Report soll **Stand Tagesende** alle Buchungen auswerten.
|
||||
- Parallel buchen die Nutzer weiter.
|
||||
|
||||
Mit MVCC:
|
||||
|
||||
- Report bekommt einen Snapshot (z.B. Stand 23:59).
|
||||
- Er arbeitet vielleicht 30 Minuten oder länger.
|
||||
- Währenddessen können Buchungen von 00:00–00:30 weiter eingehen.
|
||||
- Report sieht einen stabilen Zustand; neue Buchungen tauchen erst im nächsten Report auf.
|
||||
|
||||
Das ist ideal für:
|
||||
|
||||
- Data Warehouse Light
|
||||
- tägliche Berichte
|
||||
- Audits (reproduzierbare Sicht)
|
||||
|
||||
### Beispiel 3: Problemfall lange Transaktion
|
||||
|
||||
- Ein Entwickler startet in der Entwicklungsumgebung eine Transaktion:
|
||||
|
||||
```sql
|
||||
BEGIN;
|
||||
SELECT * FROM grosse_tabelle; -- dauert lange
|
||||
-- Entwickler vergisst COMMIT oder ROLLBACK
|
||||
```
|
||||
|
||||
- Diese Transaktion bleibt offen.
|
||||
- Alle Versionen, die seit Beginn dieser Transaktion geändert wurden, müssen aufgehoben werden.
|
||||
- Vacuum/Garbage Collector kann viele alte Zeilen nicht löschen.
|
||||
- Nach Stunden/Tagen:
|
||||
- Tabellen aufgebläht,
|
||||
- Performance sinkt,
|
||||
- Admin muss offene Sessions identifizieren und beenden.
|
||||
|
||||
Lernpunkt:
|
||||
Mit MVCC muss man auf **offene, vergessene Transaktionen** achten.
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
- **MVCC** bedeutet: Zeilen werden nicht einfach überschrieben, sondern es gibt mehrere Versionen derselben Zeile.
|
||||
- Leser und Schreiber können gleichzeitig arbeiten:
|
||||
- Leser sehen einen konsistenten Snapshot,
|
||||
- Schreiber erzeugen neue Versionen, ohne Leser direkt zu blockieren.
|
||||
- MVCC ist der Mechanismus, auf dem Isolationsebenen wie **Snapshot Isolation** aufbauen.
|
||||
- Vorteile:
|
||||
- Hohe Parallelität,
|
||||
- Weniger Sperrkonflikte,
|
||||
- Konsistente Sichten für Reports.
|
||||
- Nachteile/Herausforderungen:
|
||||
- Mehr Speicherbedarf durch alte Versionen,
|
||||
- Notwendigkeit von Aufräumprozessen,
|
||||
- Vorsicht bei langen Transaktionen,
|
||||
- bestimmte Anomalien (z.B. Write Skew) bei Snapshot Isolation.
|
||||
Reference in New Issue
Block a user