Detaillierte Erläuterung des MySQL MVCC-Mechanismusprinzips

Detaillierte Erläuterung des MySQL MVCC-Mechanismusprinzips

Was ist MVCC

MVCC, dessen vollständiger Name Multi-Version Concurrency Control lautet, ist eine Multiversion-Concurrency-Control. MVCC ist eine Methode zur Parallelitätskontrolle, die im Allgemeinen in Datenbankverwaltungssystemen verwendet wird, um den gleichzeitigen Zugriff auf Datenbanken und Transaktionsspeicher in Programmiersprachen zu implementieren.

Wir wissen, dass wir im Allgemeinen die Innodb-Speicher-Engine verwenden, wenn wir die MySQL-Datenbank verwenden. Die Innodb-Speicher-Engine unterstützt Transaktionen. Wenn also mehrere Threads gleichzeitig Transaktionen ausführen, können Parallelitätsprobleme auftreten. Zu diesem Zeitpunkt wird eine Methode benötigt, die die Parallelität steuern kann, und MVCC übernimmt diese Rolle.

Mysql-Sperre und Transaktionsisolationsebene

Bevor Sie die Prinzipien des MVCC-Mechanismus verstehen, müssen Sie zunächst den MySQL-Sperrmechanismus und die Transaktionsisolationsebene verstehen. Wenn man die MyISAM-Speicher-Engine außer Acht lässt, gibt es für die Innodb-Speicher-Engine zwei Arten von Sperren: Zeilensperren und Tabellensperren. Tabellensperren sperren die gesamte Tabelle in einem Vorgang, was die größte Sperrgranularität, aber die geringste Leistung aufweist und keine Deadlocks verursacht. Die Zeilensperre sperrt jeweils eine Zeile. Dies hat eine geringe Sperrgranularität und hohe Parallelität zur Folge, kann jedoch zu einem Deadlock führen.

Innodb-Zeilensperren werden in gemeinsame Sperren (Lesesperren) und exklusive Sperren (Schreibsperren) unterteilt. Wenn eine Transaktion einer Zeile eine Lesesperre hinzufügt, dürfen andere Transaktionen die Zeile lesen, Schreibvorgänge sind jedoch nicht zulässig. Andere Transaktionen dürfen der Zeile ebenfalls keine Schreibsperre hinzufügen, eine Lesesperre kann jedoch hinzugefügt werden.

Wenn eine Transaktion einer Zeile eine Schreibsperre hinzufügt, dürfen andere Transaktionen nicht in diese Zeile schreiben, sie können sie aber lesen. Gleichzeitig dürfen andere Transaktionen dieser Zeile keine Lese-/Schreibsperre hinzufügen.

Werfen wir einen Blick auf die Transaktionsisolationsebenen von MySQL, die in die folgenden vier Ebenen unterteilt sind:

  1. Nicht festgeschriebenes Lesen: Eine Transaktion kann Daten lesen, die von anderen Transaktionen noch nicht festgeschrieben wurden, was zu „Dirty Reads“ führt. Beispielsweise gibt es eine Gehaltstabelle. Zuerst wird Transaktion A gestartet und dann das Gehalt des Mitarbeiters mit der ID 1 abgefragt. Angenommen, das Gehalt beträgt zu diesem Zeitpunkt 1000. Zu diesem Zeitpunkt wird auch Transaktion B gestartet und ein Aktualisierungsvorgang ausgeführt, wodurch das Gehalt des Mitarbeiters mit der ID 1 um 100 reduziert wird, die Transaktion jedoch nicht festgeschrieben wird. Wenn zu diesem Zeitpunkt die Abfrageoperation von Transaktion A erneut ausgeführt wird, können die von Transaktion B aktualisierten Daten gelesen werden. Wenn Transaktion B zu diesem Zeitpunkt zurückgesetzt wird, liest Transaktion A „schmutzige“ Daten. Wenn Transaktion A einen Aktualisierungsvorgang durchführt, können auch Phantomlesevorgänge auftreten.
  2. Festgeschriebenes Lesen: Eine Transaktion kann nur Daten lesen, die von einer anderen festgeschriebenen Transaktion geändert wurden. Nachdem andere Transaktionen die Daten einmal geändert und festgeschrieben haben, kann die Transaktion den neuesten Wert abfragen. Im selben Beispiel lautet die Transaktionsisolationsebene diesmal „Read Committed“ und Transaktion B führt kein Commit für die Transaktion aus. Transaktion A kann die von Transaktion B aktualisierten Daten nicht lesen, wodurch die Generierung fehlerhafter Daten vermieden wird. Nachdem Transaktion B jedoch festgeschrieben wurde, stellt Transaktion A bei erneuter Ausführung derselben Abfrage fest, dass sich die Daten geändert haben. Dies wird als nicht wiederholbares Lesen bezeichnet, was bedeutet, dass die Ergebnisse der mehrmaligen Ausführung derselben Abfrage in derselben Transaktion inkonsistent sind. Gleichzeitig sind weiterhin Phantom-Lesevorgänge vorhanden.
  3. Wiederholbares Lesen: Nachdem eine Transaktion einen Datensatz zum ersten Mal gelesen hat, liest die Transaktion beim erneuten Lesen des Datensatzes immer noch den Wert des ersten Lesevorgangs, selbst wenn andere Transaktionen den Wert des Datensatzes ändern und ihn festschreiben. Dies ist ein wiederholbares Lesen. Diese Isolationsebene löst das Problem der Nichtwiederholbarkeit, aber es können immer noch Phantomlesevorgänge auftreten.
  4. Serialisierung: Diese Isolationsebene verursacht keine Dirty Reads oder Phantom Reads, da alle Vorgänge am selben Datensatz seriell sind. Dies ist jedoch keine gleichzeitige Transaktion.

MySQL-Rückgängig-Protokoll

MVCC verlässt sich auf der untersten Ebene auf das Undo-Protokoll von MySQL. Das Undo-Protokoll zeichnet die Vorgänge der Datenbank auf. Da das Undo-Protokoll ein logisches Protokoll ist, kann man verstehen, dass beim Löschen eines Datensatzes das Undo-Protokoll einen entsprechenden Einfügedatensatz aufzeichnet. Wenn ein Datensatz aktualisiert wird, zeichnet das Undo-Protokoll einen entgegengesetzten Aktualisierungsdatensatz auf. Wenn die Transaktion fehlschlägt und zurückgesetzt werden muss, kann sie zurückgesetzt werden, indem der entsprechende Inhalt im Undo-Protokoll gelesen wird. MVCC verwendet das Undo-Protokoll.

Implementierungsprinzip von MVCC

Die Implementierung von MVCC nutzt die impliziten Felder, das Undo-Protokoll und ReadView der Datenbank. Sehen wir uns zunächst die impliziten Felder an. Tatsächlich zeichnet MySQL implizit die folgenden versteckten Felder hinter jeder Zeile in der Tabelle auf: DB_TRX_ID (die ID der zuletzt geänderten (Änderungs-/Einfüge-)Transaktion), DB_ROLL_PTR (Rollback-Zeiger, der auf die vorherige Version dieses Datensatzes zeigt) und DB_ROW_ID (Auto-Increment-ID. Wenn die Datentabelle keinen Primärschlüssel hat, wird der Clustered-Index standardmäßig mit dieser ID erstellt).

Es gibt zwei Arten von Undo-Protokollen: Einfüge-Undo-Protokoll, ein Undo-Protokoll, das beim Einfügen eines neuen Datensatzes generiert wird. Es wird nur benötigt, wenn eine Transaktion zurückgesetzt wird, und kann sofort nach dem Festschreiben der Transaktion verworfen werden. Aktualisierungs-Undo-Protokoll, ein Undo-Protokoll, das beim Aktualisieren oder Löschen einer Transaktion generiert wird. Es wird nicht nur beim Zurücksetzen der Transaktion benötigt, sondern auch beim Lesen von Snapshots. Daher kann es nicht einfach so gelöscht werden. Das entsprechende Protokoll wird vom Bereinigungsthread nur dann gleichmäßig gelöscht, wenn das Protokoll nicht vom schnellen Lesen oder Zurücksetzen der Transaktion betroffen ist. MVCC verwendet ein Update-Rückgängig-Protokoll.

Tatsächlich zeichnet das Undo-Protokoll eine Versionskette auf. Angenommen, es gibt einen Datensatz in der Datenbank wie folgt:

Jetzt gibt es eine Transaktion A, die diesen Datensatz ändert und den Namen in Tom ändert. Der Operationsfluss zu diesem Zeitpunkt ist:

  • Transaktion A fügt zuerst eine Zeilensperre zum Zeilendatensatz hinzu
  • Anschließend kopieren Sie den Zeilendatensatz als alte Version in das Undo-Log
  • Ändern Sie nach dem Kopieren den Namen der Zeile in „tom“ und anschließend den Wert von DB_TRX_ID der Zeile in die ID von Transaktion A. Gehen Sie zu diesem Zeitpunkt davon aus, dass die ID von Transaktion A 1 ist, und richten Sie den DB_POLL_PTR der Zeile auf den Datensatz, der in das Rückgängig-Protokoll kopiert wurde.
  • Nachdem die Transaktion bestätigt wurde, wird die Sperre aufgehoben.

Die Situation stellt sich derzeit wie folgt dar:

Zu diesem Zeitpunkt ändert eine andere Transaktion B diesen Datensatz und ändert das Alter auf 28. Der Vorgangsablauf zu diesem Zeitpunkt ist:

  • Transaktion B fügt eine Zeilensperre zum Zeilendatensatz hinzu
  • Der Zeilendatensatz wird als alte Version in das Undo-Protokoll kopiert. Wenn das Undo-Protokoll bereits einen Datensatz enthält, wird ein neues Undo-Protokoll vor dem Undo-Protokoll des Zeilendatensatzes als Kopfzeile der verknüpften Liste eingefügt.
  • Ändern Sie nach dem Kopieren das Alter der Zeile auf 28 und ändern Sie dann den Wert von DB_TRX_ID der Zeile in die ID von Transaktion B. Gehen Sie zu diesem Zeitpunkt davon aus, dass die ID von Transaktion B 2 ist, und richten Sie den DB_POLL_PTR der Zeile auf den Datensatz, der in das Rückgängig-Protokoll kopiert wurde.
  • Heben Sie die Sperre auf, nachdem die Transaktion festgeschrieben wurde

Die Situation stellt sich derzeit wie folgt dar:

Aus dem Obigen können wir ersehen, dass Änderungen, die an derselben Datensatzzeile durch verschiedene Transaktionen oder dieselbe Transaktion vorgenommen werden, dazu führen, dass das Undo-Protokoll der Datensatzzeile eine Versionskette bildet. Der Kopf der Undo-Protokollkette ist der neueste alte Datensatz und das Ende der Kette ist der älteste alte Datensatz.

Nehmen wir nun eine Situation an. Nehmen wir an, dass weder Transaktion A noch Transaktion B festgeschrieben wurden. Zu diesem Zeitpunkt gibt es eine Transaktion C, die den Datensatz mit dem Namen Tom ändert und das Alter auf 30 ändert. Dann wird die Transaktion festgeschrieben. Die ID von Transaktion C ist 3. Ebenso wird ein Datensatz in das Undo-Protokoll eingefügt. Zu diesem Zeitpunkt ist die DB_TRX_ID des ersten Datensatzes in der Undo-Protokollversionskette 3.

Jetzt gibt es eine Transaktion D, die den Datensatz mit dem Namen Tom abfragt. Zu diesem Zeitpunkt wird das Lesen von Snapshots aktiviert. Der Snapshot ist ein Daten-Snapshot, der durch die Abfrageoperation zu Beginn der Transaktion ausgelöst wird. Das entsperrte Lesen ist standardmäßig ein Snapshot-Lesen unter der Isolationsebene „Wiederholbares Lesen“. Im Gegensatz zum Lesen von Snapshots gibt es auch ein aktuelles Lesen. Alle Aktualisierungsoperationen sind aktuelle Lesevorgänge. Beim Lesen des Snapshots wird eine Leseansicht generiert. In dem Moment, in dem die Transaktion den Snapshot-Lesen ausführt, wird ein aktueller Snapshot der Datenbank generiert, um die ID der aktuell aktiven Transaktion aufzuzeichnen und beizubehalten. Da die Transaktions-ID automatisch inkrementell ist, gilt: Je neuer die Transaktion, desto größer die ID. Die Leseansicht folgt dem Sichtbarkeitsalgorithmus, und ob sie sichtbar ist, erfordert eine gewisse Beurteilung. Neben der Aufzeichnung der aktuell aktiven Transaktions-ID zeichnet die Leseansicht auch die aktuell erstellte maximale Transaktions-ID auf. Beim Lesen eines Snapshots muss dieser mit der Leseansicht verglichen werden, um das Sichtbarkeitsergebnis zu erhalten.

Die Leseansicht vergleicht hauptsächlich die ID der aktuellen Transaktion mit der ID der aktiven Transaktion im System. Die Vergleichsregeln lauten wie folgt:

Erstens enthält die Leseansicht ein Array von Transaktions-IDs, die zum Zeitpunkt der Generierung der Leseansicht im System aktiv sind und vorübergehend id_list genannt werden.

Anschließend zeichnet die Leseansicht die kleinste Transaktions-ID in der ID-Liste auf, die vorübergehend als „low_id“ bezeichnet wird.

Schließlich zeichnet die Leseansicht auch eine Transaktions-ID auf, die beim Generieren der Leseansicht im System nicht zugewiesen wurde. Dies ist die aktuell größte Transaktions-ID + 1, die vorübergehend als high_id bezeichnet wird.

  • Wenn die aktuelle Transaktions-ID kleiner als low_id ist, ist die aktuelle Transaktion sichtbar
  • Wenn die aktuelle Transaktions-ID größer als high_id ist, ist die aktuelle Transaktion nicht sichtbar.
  • Die aktuelle Transaktion ist größer als low_id und kleiner als high_id. Bestimmen Sie dann, ob sie in id_list enthalten ist. Wenn dies der Fall ist, bedeutet dies, dass die aktive Transaktion noch nicht festgeschrieben wurde. Die aktuelle Transaktion ist nicht sichtbar, aber für die aktive Transaktion selbst sichtbar. Wenn sie nicht in id_list enthalten ist, ist die aktuelle Transaktion sichtbar

Wenn das Sichtbarkeitsergebnis unsichtbar ist, müssen Sie DB_ROLL_PTR verwenden, um die DB_TRX_ID des Datensatzes zum Vergleich aus dem Undo-Protokoll abzurufen. Indem Sie die Versionskette durchlaufen, bis eine DB_TRX_ID gefunden wird, die bestimmte Bedingungen erfüllt, ist der alte Datensatz mit dieser DB_TRX_ID die neueste alte Version, die die aktuelle Transaktion sehen kann.

Oben finden Sie den ausführlichen Inhalt der detaillierten Erklärung des Prinzips des MySQL-MVCC-Mechanismus. Weitere Informationen zum Prinzip des MySQL-MVCC-Mechanismus finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Detaillierte Erläuterung der MySQL-Transaktionsisolationsebene und des MVCC
  • Wie wird die Transaktionsisolation von MySQL erreicht?
  • Tiefgreifendes Verständnis der Probleme mit der Transaktionsisolationsebene und dem Sperrmechanismus von MySQL
  • Lösen Sie das Problem des MySql8.0-Prüfungsfehlers der Transaktionsisolationsebene
  • Analyse des zugrunde liegenden Prinzips der MySQL-Mehrversions-Parallelitätskontrolle MVCC
  • Implementierung von MySQL Multi-version Concurrency Control MVCC
  • Details zur Mysql MVCC-Mehrversions-Parallelitätssteuerung
  • MySQL-Transaktionsisolationsebene und MVCC

<<:  So richten Sie domänenübergreifenden Zugriff in IIS web.config ein

>>:  So behalten Sie den Inhalt im Container, wenn das Flex-Layout durch untergeordnete Elemente gestreckt wird

Artikel empfehlen

Detaillierte Erklärung der Kernfunktionen und der Ereignisbehandlung von jQuery

Inhaltsverzeichnis Ereignis Seite wird geladen Ve...

Lösung zur automatischen Beendigung von Docker Run-Containern

Heute ist bei mir ein Problem aufgetreten, als ic...

Kontext und Eigenschaften von React erklärt

Inhaltsverzeichnis 1. Kontext 1. Anwendungsszenar...

Typische Fälle von MySQL-Indexfehlern

Inhaltsverzeichnis Typische Fälle Anhang: Häufige...

4 flexible SCSS-Kompilierungsausgabestile

Vielen Leuten wird das Kompilieren erklärt, sobal...

Detaillierte Erklärung zu MySQL und Springs Autocommit

1 MySQL Autocommit-Einstellungen MySQL führt stan...

Ungültige Lösung beim Definieren mehrerer Klassenattribute in HTML

Beim Schreiben von HTML definieren wir häufig mehr...

Beispiel für reines CSS zum Ändern des Bildlaufleistenstils des Browsers

Verwenden Sie CSS, um den Stil der Bildlaufleiste...

Lösen Sie das Problem des MySQL Threads_running-Surge und der langsamen Abfrage

Inhaltsverzeichnis Hintergrund Problembeschreibun...