So lösen Sie das Phantomleseproblem in MySQL

So lösen Sie das Phantomleseproblem in MySQL

Vorwort

Wir wissen, dass MySQL den von anderen Transaktionen übermittelten Inhalt unter der Isolationsebene für wiederholbares Lesen nicht sehen kann. Unter der festschreibbaren Isolationsebene können Sie die Festschreibung anderer Transaktionen sehen. Wenn unser Geschäftsszenario darin besteht, dass die Daten, die wir für die gleichen beiden Abfragen innerhalb einer Transaktion sehen müssen, konsistent sind und nicht von anderen Transaktionen beeinflusst werden können, verwenden wir die wiederholbare Leseisolationsebene. In diesem Fall verlassen sich normale Abfragen (Snapshot-Lesevorgänge) auf RR-Ebene auf MVCC, um das Problem des „Phantomlesens“ zu lösen. Wenn es sich um eine „aktuelle Lese“-Situation handelt, worauf müssen wir uns dann verlassen, um das Problem des „Phantomlesens“ zu lösen? Darum geht es in diesem Blogbeitrag.

Bevor Sie dies diskutieren, können Sie den vorherigen Blog-Beitrag lesen (Wie implementiert MySQL die Transaktionsisolierung?), in dem hauptsächlich die spezifischen technischen Details der Isolationsebene vorgestellt werden. Es kann hilfreicher sein, diesen Artikel nach dem Lesen zu lesen.

Hinweis: Die in diesem Blogbeitrag besprochenen „Phantomlesevorgänge“ beziehen sich auf solche, die unter der Isolationsebene „wiederholbarer Lesevorgang“ durchgeführt werden.

1. Was ist Phantomlesen?

Angenommen, wir haben eine Tabelle t mit der folgenden Struktur, wobei die ersten Datenzeilen lauten: (0,0,0),(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5)

TABELLE ERSTELLEN `t`
(
    `id` INT(11) NICHT NULL,
    `Schlüssel` INT(11) DEFAULT NULL,
    `Wert` INT(11) DEFAULT NULL,
    Primärschlüssel (`id`),
    SCHLÜSSEL `Wert` (`Wert`)
)ENGINE = InnoDB;
EINFÜGEN IN t
WERTE (0, 0, 0),
       (1, 1, 1),
       (2, 2, 2),
       (3, 3, 3),
       (4, 4, 4),
       (5, 5, 5)

Angenommen, Sie wählen „*“ aus, wobei „value=1“ für die Aktualisierung ist, und sperren nur diese Zeile (beachten Sie, dass dies nur eine Annahme ist) und sperren keine anderen Zeilen. Dann tritt das folgende Szenario ein:

Die drei Abfragen Q1-Q3 von Sitzung A lauten alle „select * from where value=1“ für die Aktualisierung und fragen alle Zeilen ab, bei denen „value=1“ ist.

  • T1: Q1 gibt nur eine Zeile zurück (1,1,1);
  • T2: Sitzung B aktualisiert den Wert von ID=0 auf 1. Zu diesem Zeitpunkt gibt es in Tabelle t zwei Datenzeilen mit Wert=1.
  • T3: Q3 gibt zwei Zeilen zurück (0,0,1), (1,1,1)
  • T4: Sitzung C fügt eine Zeile (6,6,1) ein. Zu diesem Zeitpunkt gibt es in Tabelle t drei Zeilen mit dem Wert=1.
  • T5: Q3 gibt drei Zeilen zurück (0,0,1), (1,1,1), (6,6,1)
  • T6: Transaktion der Sitzung A wird festgeschrieben.

Das Phänomen, dass Q3 den Wert = 1 liest, wird als Phantomlesen bezeichnet. Phantomlesen bedeutet, dass, wenn eine Transaktion denselben Bereich zweimal abfragt, die letztere Abfrage Zeilen sieht, die die erste Abfrage nicht gesehen hat.

Lassen Sie uns zunächst das „Phantomlesen“ wie folgt erklären:

  • Unter der Isolationsebene für wiederholbares Lesen handelt es sich bei gewöhnlichen Abfragen um Snapshot-Lesevorgänge, bei denen von anderen Transaktionen eingefügte Daten nicht berücksichtigt werden. Daher werden Phantom-Lesevorgänge nur unter „aktueller Lesevorgang“ angezeigt (denn in allen drei Abfragen wird „Update“ als aktueller Lesevorgang angegeben).
  • Die Aktualisierungsergebnisse der obigen Sitzung B werden von der Select-Anweisung nach Sitzung A mit „aktuellem Lesen“ angezeigt, das nicht als Phantomlesen bezeichnet werden kann. Phantomlesen bezieht sich nur auf „neu eingefügte Zeilen“.

2. Welche Probleme gibt es beim Phantomlesen?

(1) Muss separat gelöst werden

Wie wir alle wissen, sperrt die Anweisung „select ...for update“ die entsprechende Datenzeile. Beispielsweise sperrt die Abfrageanweisung Q1 von Sitzung A zum Zeitpunkt T1: „select * from where value=1 for update“ die Datenzeile mit value=1. Tritt jedoch das obige Szenario auf, wird die Semantik von „for update“ zerstört (die Datenzeile mit value=1 wird nicht gesperrt).

Auch wenn alle Datensätze gesperrt sind, lässt sich das Einfügen neuer Datensätze nicht verhindern, sodass das Problem des „Phantomlesens“ separat gelöst werden muss. Es kann nicht durch MVCC oder einen Zeilensperrmechanismus gelöst werden. Dies bringt uns zum „Gap Lock“, einem weiteren Verriegelungsmechanismus.

(2) Durch Gap-Locks verursachte Parallelität

Die Einführung von Lückensperren kann dazu führen, dass dieselbe Anweisung einen größeren Bereich sperrt, was die Parallelität beeinträchtigen kann. Weitere Einzelheiten entnehmen Sie bitte der folgenden Einführung.

3. Wie kann man das Phantomlesen lösen?

Der Grund für Phantomlesevorgänge liegt darin, dass Zeilensperren nur Zeilen sperren können, das Einfügen neuer Datensätze jedoch die „Lücken“ zwischen den Datensätzen aktualisiert. Um das Phantomleseproblem zu lösen, musste InnoDB daher eine neue Sperre einführen, nämlich die Gap Lock.

Lücke: Fügen Sie der Tabelle beispielsweise 6 Datensätze hinzu: 0, 5, 10, 15, 20, 25. Daraus ergeben sich 7 Lücken:

Während des zeilenweisen Scanvorgangs werden den Zeilen nicht nur Zeilensperren hinzugefügt, sondern den Zwischenräumen auf beiden Seiten der Zeilen auch Lückensperren. Dadurch wird sichergestellt, dass keine neuen Datensätze eingefügt werden können.

Lückensperren und Zeilensperren werden zusammen als Next-Key-Sperren bezeichnet. Jede Next-Key-Sperre ist ein Open-First-Closed-Intervall (Lückensperre offenes Intervall, Next-Key-Sperre offenes First-Closed-Intervall):

Es besteht kein Konflikt zwischen Lückensperren. Der Konflikt besteht darin, einen Datensatz in die Lücke einzufügen.

In Tabelle t gibt es keinen Datenwert = 7, daher fügt Q1 eine Lückensperre (1,5) hinzu, und Q2 fügt ebenfalls diese Lückensperre hinzu. Die beiden stehen nicht im Konflikt miteinander und sollen beide verhindern, dass die Lücke eingefügt wird.

Nachdem Tabelle t initialisiert wurde, gehen wir davon aus, dass die Daten in der Tabelle wie folgt lauten:

Wenn Sie select * from verwenden, um das Update auszuführen, werden alle Datensätze in der gesamten Tabelle gesperrt, wodurch 7 Next-Key-Sperren gebildet werden, nämlich (-∞,0], (0,2], (2,4], (4,6], (6,8], (8, 10], (10, +supremum]

Die Einführung von Lückensperren kann dazu führen, dass dieselbe Anweisung einen größeren Bereich sperrt, was sich auf die Parallelität auswirkt.

Nehmen Sie das folgende Szenario an:

Dann ist offensichtlich ein Deadlock aufgetreten. Die Analyse sieht wie folgt aus:

  • F1: Führen Sie die Anweisung select ...for update aus. Da die Zeile mit der ID = 9 nicht vorhanden ist, wird eine Lückensperre (8,10) hinzugefügt.
  • F2: Bei der Ausführung der Anweisung select ...for update wird auch die Lückensperre (8,10) hinzugefügt. Es gibt keinen Konflikt zwischen den Lückensperren, daher kann diese Anweisung erfolgreich ausgeführt werden.
  • Sitzung B versucht eine Zeile (9,9,9) einzufügen, wird jedoch durch die Lückensperre von Sitzung A blockiert und muss warten.
  • Sitzung A versucht, eine Zeile (9,9,9) einzufügen und wird durch die Lückensperre von Sitzung B blockiert.

Wie oben erwähnt, kann die Einführung von Lückensperren dazu führen, dass dieselbe Anweisung einen größeren Bereich sperrt, was sich tatsächlich auf die Parallelität auswirkt.

Um das Phantomleseproblem zu lösen, kann die Isolationsstufe „Read Committable“ verwendet werden. Die Lückensperre wird nur unter der Isolationsstufe „Repeatable Read“ wirksam. Wenn die Isolationsebene auf „Read Committed“ eingestellt ist, gibt es keine Lückensperren. Wenn Sie jedoch gleichzeitig die mögliche Inkonsistenz zwischen Daten und Protokollen beheben möchten, müssen Sie das Binlog-Format auf Zeile einstellen, d. h. die Kombination aus „RC-Isolationsstufe + Protokollformat binlog_format=row“ verwenden.

Abschluss

  • Lückensperren sind nur auf der RR-Isolationsebene gültig, und auf der RC-Isolationsebene gibt es keine Lückensperren.
  • So lösen Sie das Problem des „Phantomlesens“ auf der RR-Isolationsebene: „Snapshot-Lesen“ basiert auf der MVCC-Steuerung und „aktuelles Lesen“ wird durch Gap Lock gelöst.
  • Lückensperren und Zeilensperren werden zusammen als Next-Key-Sperren bezeichnet. Jede Next-Key-Sperre ist ein Open-First-Closed-Intervall.
  • Die Einführung von Lückensperren kann dazu führen, dass dieselbe Anweisung einen größeren Bereich sperrt, was die Parallelität beeinträchtigt.

Dies ist das Ende dieses Artikels zur Lösung des Phantomleseproblems in MySQL. Weitere Informationen zu MySQL-Phantomlesevorgängen finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Beispiel für die Verwendung von MySQL-Transaktionsfunktionen zur Implementierung einer gleichzeitigen und sicheren Auto-Increment-ID
  • Lösung für das Problem der gesperrten Transaktionsverarbeitung mit hoher Parallelität in PHP+MySQL
  • Kann die wiederholbare Leseebene von MySQL Phantomlesevorgänge lösen?
  • Detaillierte Erklärung, wie MySQL Phantom-Lesevorgänge löst
  • Lösung für das Problem der MySQL-Transaktionsparallelität
  • Detaillierte Erklärung zu MySQL-Phantomlesevorgängen und wie man sie eliminiert
  • MySQL Series 10 MySQL-Transaktionsisolierung zur Implementierung der Parallelitätskontrolle
  • mysql + mybatis implementiert gespeicherte Prozedur + Transaktion + gleichzeitigen Mehrfachabruf von Seriennummern
  • Detaillierte Erläuterung des gleichzeitigen Dirty Read + nicht wiederholbaren Read + Phantom Read in MySQL-Transaktionen

<<:  Beispiel für die Verwendung verschachtelter HTML-Seiten (Frameset-Verwendung)

>>:  Detaillierter Prozess zur Installation von Presto und zum Verbinden von Hive in Docker

Artikel empfehlen

Anwendungsbeispiele für die virtuelle Liste des WeChat-Applets

Inhaltsverzeichnis Vorwort Was ist eine virtuelle...

Einführung in die grafischen Kompositions- und Satzfunktionen des Webdesigns

Alles braucht ein Fundament. Um ein Haus zu bauen...

Vorteile von INSERT INTO SET in MySQL

Daten in MySQL-Datenbank einfügen. Bisher häufig ...

Detaillierte Erklärung der Verwendung des Linux-Befehls lsof

lsof (List Open Files) ist ein Tool zum Anzeigen ...

Implementierung der Ausführung von SQL Server mit Docker

Jetzt ist .net Core plattformübergreifend und jed...

Einfache Implementierung von HTML zum Erstellen eines persönlichen Lebenslaufs

Lebenslauf-Code: XML/HTML-CodeInhalt in die Zwisc...

So führen Sie den Top-Befehl im Batchmodus aus

Der Befehl „top“ ist der beste Befehl, den jeder ...

Eine kurze Diskussion zur MySQL-Select-Optimierungslösung

Inhaltsverzeichnis Beispiele aus dem wirklichen L...

Beispielmethode zum Anzeigen der mit MySQL verbundenen IP-Adresse

Spezifische Methode: Öffnen Sie zuerst die Eingab...

Detaillierte Analyse des Flex-Layouts in CSS3

Das Flexbox-Layoutmodul soll eine effizientere Mö...

So installieren und konfigurieren Sie Redis in CentOS7

Einführung Es ist nicht nötig, Redis im Detail vo...

JS realisiert den Effekt des Bildwasserfallflusses

In diesem Artikel wird der spezifische JS-Code zu...