Das Konzept der Mehrversionenkontrolle (MVCC, Multi-Version Concurrency Control) entstand als Alternative zu strengen Sperren, um parallel eine große Anzahl von Transaktionen zu ermöglichen. Dies war wichtig, um Konflikte und Sperren beim gleichzeitigen Datenzugriff zu reduzieren, was besonders in OLTP-Systemen von entscheidender Bedeutung ist.
Traditionelle Ansätze zur Sperrung (z.B. Zeilenebene-Sperren) können zu Verzögerungen in Anwendungen bei hoher Konkurrenz führen. Die Aufgabe von MVCC besteht darin, es Transaktionen zu ermöglichen, konsistente Schnappschüsse von Daten zu lesen, selbst wenn gleichzeitig Schreiboperationen durchgeführt werden, wodurch Isolation und gleichzeitiger Zugriff gewährleistet werden.
MVCC wird in beliebten Datenbanksystemen (PostgreSQL, Oracle, MySQL/InnoDB) durch die Speicherung von Versionshistorien von Zeilen implementiert. Beim Lesen sieht jede Transaktion nur die Zeilen, die vor ihrem Start festgeschrieben wurden, während Einfügungen/Aktualisierungen neue Versionen von Zeilen erstellen, ohne sie sofort zu löschen.
Beispiel einer Abfrage (PostgreSQL):
BEGIN TRANSACTION; SELECT * FROM orders WHERE status = 'processing'; UPDATE orders SET status = 'completed' WHERE id = 42; COMMIT;
Solange die Transaktion nicht abgeschlossen ist, sehen andere Benutzer die vorherige Version der Zeile, und erst nach dem Commit werden die Änderungen neuen Transaktionen zugänglich.
Wichtige Merkmale:
Kann MVCC alle Arten von Sperren und Konflikten vollständig eliminieren?
Nein, auch bei MVCC sind Konflikte möglich, wenn gleichzeitig dieselben Zeilen aktualisiert werden — beispielsweise bei gleichzeitigen UPDATEs tritt ein Konflikt bei den Commits (write-write conflict) auf, und das DBMS gibt einen Fehler aus oder rollt eine der Transaktionen zurück.
Wann werden alte Versionen von Zeilen in MVCC entfernt, und kann dies zu Speicherlecks führen?
In den meisten DBMS werden alte Versionen von Zeilen durch spezielle Prozesse (VACUUM in PostgreSQL) entfernt. Wenn diese Prozesse nicht ausgeführt werden, "quillt" die Datenbank über und die Leistung leidet.
Funktionieren "select for update" korrekt unter MVCC-Bedingungen, und warum ist Locking erforderlich?
Ja, SELECT FOR UPDATE-Abfragen blockieren Zeilen, um Konflikte bei parallel durchgeführten Änderungen zu vermeiden, andernfalls könnte es zu "verlorenen Updates" kommen.
Beispiel:
BEGIN; SELECT * FROM products WHERE id = 123 FOR UPDATE; UPDATE products SET quantity = quantity - 1 WHERE id = 123; COMMIT;
In einem großen Online-Shop wurde ein Schema mit häufigen UPDATEs von Bestellungen ohne VACUUM-Einstellung implementiert. Nach einem Monat wuchs die Datenbank um das 10-fache, Abfragen verlangsamten sich drastisch.
Vorteile:
Nachteile:
Es wurde ein regelmäßiges Autovacuum implementiert, write-conflict-Kontrollen verwendet, Isolation auf REPEATABLE READ nur für kritische Abfragen angewendet.
Vorteile:
Nachteile: