Het concept van multiversioning (MVCC, Multi-Version Concurrency Control) is ontstaan als alternatief voor strikte locks, om de gelijktijdige werking van een groot aantal transacties te waarborgen. Dit was belangrijk om conflicten en blokkeringen te verminderen bij gelijktijdige toegang tot gegevens, wat vooral kritisch is in OLTP-systemen.
Traditionele benaderingen van locking (bijvoorbeeld row-level locking) kunnen leiden tot vertragingen in applicaties bij hoge concurrentie. De taak van MVCC is om transacties in staat te stellen consistente snapshots van gegevens te lezen, zelfs als er tegelijkertijd schrijfoperaties plaatsvinden, en zo isolatie en gelijktijdige toegang te waarborgen.
MVCC wordt geïmplementeerd in populaire DBMS (PostgreSQL, Oracle, MySQL/InnoDB) door versies van rijen op te slaan. Bij het lezen ziet elke transactie alleen de rijen die zijn vastgelegd voordat deze start, terwijl invoegingen/bijwerkingen nieuwe versies van rijen creëren zonder onmiddellijke verwijdering.
Voorbeeld van een query (PostgreSQL):
BEGIN TRANSACTION; SELECT * FROM orders WHERE status = 'processing'; UPDATE orders SET status = 'completed' WHERE id = 42; COMMIT;
Zolang de transactie niet is voltooid, zullen andere gebruikers de vorige versie van de rij zien, en pas na de commit worden de wijzigingen beschikbaar voor nieuwe transacties.
Belangrijke kenmerken:
Kan MVCC volledig alle soorten blokkeringen en conflicten elimineren?
Nee, in MVCC kunnen er nog steeds conflicten optreden bij gelijktijdige bijwerkingen van dezelfde rijen — bijvoorbeeld, bij gelijktijdige UPDATE's ontstaat er een commit-conflict (write-write conflict), en de DBMS genereert een fout of maakt een van de transacties ongedaan.
Wanneer worden oude versies van rijen verwijderd in MVCC en kan dit leiden tot geheugenlekken?
In de meeste DBMS worden oude versies van rijen verwijderd door speciale processen (VACUUM in PostgreSQL). Als deze processen niet worden uitgevoerd, "groeit" de database en daalt de prestaties.
Werken "select for update" correct in een MVCC-omgeving, en waarom is locking nodig?
Ja, SELECT FOR UPDATE queries blokkeren rijen om conflicten bij gelijktijdige wijzigingen te voorkomen; anders zouden er "verloren updates" kunnen optreden.
Voorbeeld:
BEGIN; SELECT * FROM products WHERE id = 123 FOR UPDATE; UPDATE products SET quantity = quantity - 1 WHERE id = 123; COMMIT;
In een grote online winkel werd een schema met frequente UPDATE's van bestellingen geïmplementeerd zonder VACUUM-configuratie. Na een maand was de database 10 keer gegroeid en waren de queries aanzienlijk vertraagd.
Voordelen:
Nadelen:
Er is een regelmatige autovacuum geïmplementeerd, write-conflict controle wordt toegepast, en isolatie op het niveau van REPEATABLE READ alleen voor kritieke queries.
Voordelen:
Nadelen: