Heim > Datenbank > MySQL-Tutorial > Hauptteil

MySQL fasst das MVCC-Prinzip von InnoDB zusammen

WBOY
Freigeben: 2022-04-18 18:25:04
nach vorne
2057 Leute haben es durchsucht

Dieser Artikel vermittelt Ihnen relevantes Wissen über MySQL, das hauptsächlich Probleme im Zusammenhang mit dem MVCC-Prinzip von InnoDB vorstellt, der Parallelitätskontrolle mehrerer Versionen, hauptsächlich zur Verbesserung der Parallelitätsleistung der Datenbank hoffe es hilft allen.

MySQL fasst das MVCC-Prinzip von InnoDB zusammen

Empfohlenes Lernen: MySQL-Video-Tutorial

MVCC steht für Multi-Version Concurrency Control, eine Parallelitätskontrolle für mehrere Versionen, die hauptsächlich der Verbesserung der Parallelitätsleistung der Datenbank dient. Wenn eine Lese- oder Schreibanforderung für dieselbe Datenzeile auftritt, wird diese gesperrt und blockiert. MVCC verwendet jedoch eine bessere Methode zur Verarbeitung von Lese-/Schreibanforderungen, sodass keine Sperrung auftritt, wenn ein Konflikt mit Lese-/Schreibanforderungen auftritt. Dieser Lesevorgang bezieht sich auf den Snapshot-Lesevorgang, nicht auf den aktuellen Lesevorgang. Der aktuelle Lesevorgang ist ein Sperrvorgang und eine pessimistische Sperre. Wie wird also Lesen und Schreiben ohne Sperren erreicht? Was bedeuten Snapshot-Lesen und aktuelles Lesen? Das werden wir alle später erfahren.

MySQL kann Phantom-Leseprobleme unter der Isolationsstufe REPEATABLE READ weitgehend vermeiden.

Versionskette

Wir wissen, dass für Tabellen, die die InnoDB-Speicher-Engine verwenden, die Clustered-Index-Datensätze zwei erforderliche versteckte Spalten enthalten (row_id ist nicht erforderlich, die von uns erstellte Tabelle verfügt über einen Primärschlüssel oder einen nicht NULL UNIQUE-Schlüssel die Spalte „row_id“ nicht einschließen):

  • trx_id: Jedes Mal, wenn eine Transaktion einen Clustered-Index-Datensatz ändert, wird die Transaktions-ID der Transaktion der ausgeblendeten Spalte „trx_id“ zugewiesen.

  • roll_pointer: Jedes Mal, wenn ein Clustered-Index-Datensatz geändert wird, wird die alte Version in das Rückgängig-Protokoll geschrieben. Dann entspricht diese versteckte Spalte einem Zeiger, der verwendet werden kann, um den Datensatz vor der Änderung zu finden.

Um dieses Problem zu veranschaulichen, erstellen wir eine Demotabelle:

CREATE TABLE `teacher` (
  `number` int(11) NOT NULL,
  `name` varchar(100) DEFAULT NULL,
  `domain` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`number`)) ENGINE=InnoDB DEFAULT CHARSET=utf8
Nach dem Login kopieren

Fügen Sie dann ein Datenelement in diese Tabelle ein:

mysql> insert into teacher values(1, 'J', 'Java');Query OK, 1 row affected (0.01 sec)
Nach dem Login kopieren

Die Daten sehen jetzt so aus:

mysql> select * from teacher;
+--------+------+--------+
| number | name | domain |
+--------+------+--------+
|      1 | J    | Java   |
+--------+------+--------+
1 row in set (0.00 sec)
Nach dem Login kopieren

Angenommen, die Transaktions-ID des eingefügten Datensatzes ist 60, dann sieht das schematische Diagramm des Datensatzes in diesem Moment wie folgt aus:

MySQL fasst das MVCC-Prinzip von InnoDB zusammen

Angenommen, zwei Transaktionen mit den Transaktions-IDs 80 und 120 führen UPDATE-Vorgänge für diesen Datensatz aus. Der Vorgang ist wie folgt:

Trx80 Trx120
beginnen

beginnen
Lehrersatzname='S' aktualisieren, wo. Nummer= 1;
Lehrer aktualisieren set name='T ' where number=1;
commit

update teacher set name = 'K' where number=1; =' F' where number=1 ;

commit

每次对记录进行改动,都会记录一条undo日志,每条undo日志也都有一个roll_pointer属性(INSERT操作对应的undo日志没有该属性,因为该记录并没有更早的版本),可以将这些undo日志都连起来,串成一个链表,所以现在的情况就像下图一样:

MySQL fasst das MVCC-Prinzip von InnoDB zusammen

对该记录每次更新后,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。另外,每个版本中还包含生成该版本时对应的事务id。于是可以利用这个记录的版本链来控制并发事务访问相同记录的行为,那么这种机制就被称之为多版本并发控制(Mulit-Version Concurrency Control MVCC)。

ReadView

对于使用READ UNCOMMITTED隔离级别的事务来说,由于可以读到未提交事务修改过的记录,所以直接读取记录的最新版本就好了。

对于使用SERIALIZABLE隔离级别的事务来说,InnoDB使用加锁的方式来访问记录。

对于使用READ COMMITTED和REPEATABLE READ隔离级别的事务来说,都必须保证读到已经提交了的事务修改过的记录,也就是说假如另一个事务已经修改了记录但是尚未提交,是不能直接读取最新版本的记录的,核心问题就是:READ COMMITTED和REPEATABLE READ隔离级别在不可重复读和幻读上的区别,这两种隔离级别关键是需要判断一下版本链中的哪个版本是当前事务可见的。

为此,InnoDB提出了一个ReadView的概念,这个ReadView中主要包含4个比较重要的内容:

  • m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。

  • min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。

  • max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。注意max_trx_id并不是m_ids中的最大值,事务id是递增分配的。比方说现在有id为1,2,3这三个事务,之后id为3的事务提交了。那么一个新的读事务在生成ReadView时,m_ids就包括1和2,min_trx_id的值就是1,max_trx_id的值就是4。

  • creator_trx_id:表示生成该ReadView的事务的事务id。

有了这个ReadView,这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见:

  1. 如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
  2. 如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。
  3. 如果被访问版本的trx_id属性值大于或等于ReadView中的max_trx_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。
  4. 如果被访问版本的trx_id属性值在ReadView的min_trx_id和max_trx_id之间(min_trx_id
  5. 如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见,查询结果就不包含该记录。

在MySQL中,READ COMMITTED和REPEATABLE READ隔离级别的的一个非常大的区别就是它们生成ReadView的时机不同。

我们还是以表teacher为例,假设现在表teacher中只有一条由事务id为60的事务插入的一条记录,接下来看一下READ COMMITTED和REPEATABLE READ所谓的生成ReadView的时机不同到底不同在哪里。

READ COMMITTED每次读取数据前都生成一个ReadView

假设现在系统里有两个事务id分别为80、120的事务在执行:

# Transaction 80
set session transaction isolation level read committed;
begin
update teacher set name='S' where number=1;
update teacher set name='T' where number=1;
Nach dem Login kopieren

此刻,表teacher中number为1的记录得到的版本链表如下所示:

MySQL fasst das MVCC-Prinzip von InnoDB zusammen

假设现在有一个使用READ COMMITTED隔离级别的事务开始执行:

set session transaction isolation level read committed;
# 使用READ COMMITTED隔离级别的事务
begin;
# SELECE1:Transaction 80、120未提交
SELECT * FROM teacher WHERE number = 1; # 得到的列name的值为'J'
Nach dem Login kopieren

这个SELECE1的执行过程如下:

  • 在执行SELECT语句时会先生成一个ReadView,ReadView的m_ids列表的内容就是[80, 120],min_trx_id为80,max_trx_id为121,creator_trx_id为0。

  • 然后从版本链中挑选可见的记录,最新版本的列name的内容是’T’,该版本的trx_id值为80,在m_ids列表内,根据步骤4不符合可见性要求,根据roll_pointer跳到下一个版本。

  • 下一个版本的列name的内容是’S’,该版本的trx_id值也为80,也在m_ids列表内,根据步骤4也不符合要求,继续跳到下一个版本。

  • 下一个版本的列name的内容是’J’,该版本的trx_id值为60,小于ReadView 中的min_trx_id值,根据步骤2判断这个版本是符合要求的。

之后,我们把事务id为80的事务提交一下,然后再到事务id为120的事务中更新一下表teacher 中number为1的记录:

set session transaction isolation level read committed;
# Transaction 120
begin
update teacher set name='K' where number=1;
update teacher set name='F' where number=1;
Nach dem Login kopieren

此刻,表teacher 中number为1的记录的版本链就长这样:

MySQL fasst das MVCC-Prinzip von InnoDB zusammen

然后再到刚才使用READ COMMITTED隔离级别的事务中继续查找这个number 为1的记录,如下:

# 使用READ COMMITTED隔离级别的事务
begin;
# SELECE1:Transaction 80、120未提交
SELECT * FROM teacher WHERE number = 1; # 得到的列name的值为'J'
# SELECE2:Transaction 80提交、120未提交
SELECT * FROM teacher WHERE number = 1; # 得到的列name的值为'T'
Nach dem Login kopieren

这个SELECE2 的执行过程如下:

  • 在执行SELECT语句时会又会单独生成一个ReadView,该ReadView的m_ids列表的内容就是[120](事务id为80的那个事务已经提交了,所以再次生成快照时就没有它了),min_trx_id为120,max_trx_id为121,creator_trx_id为0。
  • 然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列name的内容是’F’,该版本的trx_id值为120,在m_ids列表内,根据步骤4不符合可见性要求,根据roll_pointer跳到下一个版本。
  • 下一个版本的列name 的内容是’K’,该版本的trx_id值为120,也在m_ids列表内,根据步骤4不符合可见性要求,根据roll_pointer跳到下一个版本。
  • 下一个版本的列name的内容是’T’,该版本的trx_id值为80,小于ReadView中的min_trx_id值120,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以这个版本是符合要求的,最后返回给用户的版本就是这条列name为’‘T’'的记录。

以此类推,如果之后事务id为120的记录也提交了,再次在使用READCOMMITTED隔离级别的事务中查询表teacher中number值为1的记录时,得到的结果就是’F’了,具体流程我们就不分析了。

总结一下就是:使用READCOMMITTED隔离级别的事务在每次查询开始时都会生成一个独立的ReadView。

REPEATABLE READ —— 在第一次读取数据时生成一个ReadView

对于使用REPEATABLE READ隔离级别的事务来说,只会在第一次执行查询语句时生成一个ReadView,之后的查询就不会重复生成了。我们还是用例子看一下是什么效果。

假设现在系统里有两个事务id分别为80、120的事务在执行:

# Transaction 80
begin
update teacher set name='S' where number=1;
update teacher set name='T' where number=1;
Nach dem Login kopieren

此刻,表teacher中number为1的记录得到的版本链表如下所示:

MySQL fasst das MVCC-Prinzip von InnoDB zusammen

假设现在有一个使用REPEATABLE READ隔离级别的事务开始执行:

# 使用REPEATABLE READ隔离级别的事务
begin;
# SELECE1:Transaction 80、120未提交
SELECT * FROM teacher WHERE number = 1; # 得到的列name的值为'J'
Nach dem Login kopieren

这个SELECE1的执行过程如下(与READ COMMITTED的过程一致):

  • 在执行SELECT语句时会先生成一个ReadView,ReadView的m_ids列表的内容就是[80, 120],min_trx_id为80,max_trx_id为121,creator_trx_id为0。

  • 然后从版本链中挑选可见的记录,最新版本的列name的内容是’T’,该版本的trx_id值为80,在m_ids列表内,根据步骤4不符合可见性要求,根据roll_pointer跳到下一个版本。

  • 下一个版本的列name的内容是’S’,该版本的trx_id值也为80,也在m_ids列表内,根据步骤4也不符合要求,继续跳到下一个版本。

  • 下一个版本的列name的内容是’J’,该版本的trx_id值为60,小于ReadView 中的min_trx_id值,根据步骤2判断这个版本是符合要求的。

之后,我们把事务id为80的事务提交一下,然后再到事务id为120的事务中更新一下表teacher 中number为1的记录:

# Transaction 80
begin
update teacher set name='K' where number=1;
update teacher set name='F' where number=1;
Nach dem Login kopieren

此刻,表teacher 中number为1的记录的版本链就长这样:

MySQL fasst das MVCC-Prinzip von InnoDB zusammen

然后再到刚才使用REPEATABLE READ隔离级别的事务中继续查找这个number为1的记录,如下:

# 使用REPEATABLE READ隔离级别的事务
begin;
# SELECE1:Transaction 80、120未提交
SELECT * FROM teacher WHERE number = 1; # 得到的列name的值为'J'
# SELECE2:Transaction 80提交、120未提交
SELECT * FROM teacher WHERE number = 1; # 得到的列name的值为'J'
Nach dem Login kopieren

这个SELECE2的执行过程如下:

  • Da die Isolationsstufe der aktuellen Transaktion REPEATABLE READ ist und ReadView bereits beim Ausführen von SELECE1 generiert wurde, wird die vorherige ReadView zu diesem Zeitpunkt direkt wiederverwendet. Der Inhalt der m_ids-Liste der vorherigen ReadView ist [80, 120 ], min_trx_id ist 80, max_trx_id ist 121 und Creator_trx_id ist 0.
  • Wählen Sie dann die sichtbaren Datensätze aus der Versionskette aus. Wie aus der Abbildung hervorgeht, ist der Inhalt des Spaltennamens der neuesten Version „F“. Der trx_id-Wert dieser Version ist 120. In der m_ids-Liste ist es ist gemäß Schritt 4 nicht sichtbar. Sexuelle Anforderungen, springen Sie zur nächsten Version gemäß roll_pointer.
  • Der Inhalt des Spaltennamens der nächsten Version ist 'K'. Der trx_id-Wert dieser Version ist 120, was laut Schritt 4 nicht den Sichtbarkeitsanforderungen entspricht und zu springt nächste Version gemäß roll_pointer.
  • Der Inhalt des Spaltennamens der nächsten Version ist 'T'. Der trx_id-Wert dieser Version ist 80, was laut Schritt 4 nicht den Sichtbarkeitsanforderungen entspricht und zu springt nächste Version gemäß roll_pointer.
  • Der Inhalt des Spaltennamens der nächsten Version ist 'S'. Der trx_id-Wert dieser Version ist 80, was laut Schritt 4 nicht den Sichtbarkeitsanforderungen entspricht und zu springt nächste Version gemäß roll_pointer.
  • Der Inhalt des Spaltennamens der nächsten Version ist „J“. Der trx_id-Wert dieser Version ist 60, was kleiner als der min_trx_id-Wert 80 in ReadView ist, was darauf hinweist, dass die Transaktion, die diese Version generiert hat, vor dem festgeschrieben wurde Die aktuelle Transaktion generiert ReadView, sodass diese Version vorhanden ist. Wenn die Anforderungen erfüllt sind, ist die endgültige an den Benutzer zurückgegebene Version der Datensatz mit dem Spaltennamen „J“.

Das heißt, die durch die beiden SELECT-Abfragen erhaltenen Ergebnisse werden wiederholt und die aufgezeichneten Spaltenwerte sind alle „J“. Dies ist die Bedeutung von wiederholbarem Lesen.

Wenn wir den Datensatz mit der Transaktions-ID 120 später übermitteln und dann in der Transaktion, die gerade die Isolationsstufe REPEATABLE READ verwendet hat, weiter nach dem Datensatz mit der Nummer 1 suchen, lautet das Ergebnis immer noch „J“. Sie können das Spezifische überprüfen Ausführungsprozess Analysieren Sie es selbst.

Phantom-Lese-Phänomen und Phantom-Lese-Lösung unter MVCC

Wir wissen bereits, dass MVCC das Problem des nicht wiederholbaren Lesens unter der Isolationsstufe REPEATABLE READ lösen kann, aber was ist mit Phantom-Lesen? Wie wird MVCC gelöst? Beim Phantomlesen liest eine Transaktion Datensätze mehrmals unter denselben Bedingungen. Der letzte Lesevorgang liest einen Datensatz, der zuvor noch nicht gelesen wurde, und dieser Datensatz stammt aus einem neuen Datensatz, der von einer anderen Transaktion hinzugefügt wurde.

Wir können darüber nachdenken: Transaktion T1 unter der Isolationsstufe REPEATABLE READ liest zuerst mehrere Datensätze basierend auf einer bestimmten Suchbedingung, dann fügt Transaktion T2 einen Datensatz ein, der die entsprechende Suchbedingung erfüllt, und sendet ihn, und dann sucht Transaktion T1 basierend darauf die gleiche bedingte Ausführung der Abfrage. Was wird das Ergebnis sein? Gemäß den Vergleichsregeln in ReadView:

Unabhängig davon, ob Transaktion T2 vor Transaktion T1 geöffnet wird, kann Transaktion T1 die Übermittlung von T2 nicht sehen. Bitte analysieren Sie es selbst gemäß den oben eingeführten Regeln für Versionskette, ReadView und Sichtbarkeitsbeurteilung.

Allerdings kann MVCC in InnoDB unter der Isolationsstufe REPEATABLE READ das Phantomlesen weitgehend vermeiden, anstatt das Phantomlesen vollständig zu verbieten. Was ist los? Schauen wir uns die folgende Situation an:

T1 T2
begin;
select * from teacher where number=30; No data begin;

In Lehrerwerte einfügen (30, 'X', 'Java');

commit;
Lehrer-Set-Domain='MQ' aktualisieren, wobei Nummer=30 ist; Wählen Sie * aus Lehrer mit Zahl = 30; hat Daten

Nun, was ist los? Transaktion T1 weist offensichtlich ein Phantomlesephänomen auf. Unter der Isolationsstufe REPEATABLE READ generiert T1 eine ReadView, wenn zum ersten Mal eine normale SELECT-Anweisung ausgeführt wird, und dann fügt T2 einen neuen Datensatz in die Lehrertabelle ein und übermittelt ihn. ReadView kann T1 nicht daran hindern, die UPDATE- oder DELETE-Anweisung auszuführen, um den neu eingefügten Datensatz zu ändern (da T2 bereits übermittelt wurde, führt eine Änderung des Datensatzes nicht zu einer Blockierung), aber auf diese Weise wird der Wert der ausgeblendeten Spalte trx_id dieses neuen Datensatzes geändert be Es wird zur Transaktions-ID von T1. Danach kann T1 diesen Datensatz sehen, wenn er eine gewöhnliche SELECT-Anweisung zum Abfragen dieses Datensatzes verwendet, und diesen Datensatz an den Client zurückgeben. Aufgrund der Existenz dieses besonderen Phänomens können wir auch davon ausgehen, dass MVCC das Phantomlesen nicht vollständig verbieten kann.

MVCC-Zusammenfassung

Aus der obigen Beschreibung können wir ersehen, dass sich das sogenannte MVCC (Multi-Version ConcurrencyControl, Multi-Version-Parallelitätskontrolle) auf die Verwendung der beiden Isolationsstufen READ COMMITTD und REPEATABLE READ zur Ausführung gewöhnlicher Transaktionen bezieht Bei der SELECT-Operation handelt es sich um den Prozess des Zugriffs auf die aufgezeichnete Versionskette. Dadurch können die Lese-/Schreib- und Schreib-/Lesevorgänge verschiedener Transaktionen gleichzeitig ausgeführt werden, wodurch die Systemleistung verbessert wird.

Ein großer Unterschied zwischen den beiden Isolationsstufen READ COMMITTD und REPEATABLE READ besteht darin, dass der Zeitpunkt der Generierung von ReadView unterschiedlich ist. READ COMMITTD generiert vor jeder gewöhnlichen SELECT-Operation eine ReadView, während REPEATABLE READ nur zum ersten Mal eine ReadView generiert Generieren Sie einfach eine ReadView vor der SELECT-Operation und verwenden Sie diese ReadView für nachfolgende Abfragevorgänge wieder, um so das Phänomen des Phantomlesens zu vermeiden.

Wir sagten zuvor, dass die Ausführung einer DELETE-Anweisung oder einer UPDATE-Anweisung, die den Primärschlüssel aktualisiert, den entsprechenden Datensatz nicht sofort von der Seite löscht, sondern eine sogenannte Löschmarkierungsoperation ausführt, die dem einfachen Setzen von a entspricht Löschflag für den Datensatz. Dies gilt hauptsächlich für MVCC. Darüber hinaus wird das sogenannte MVCC nur dann wirksam, wenn wir gewöhnliche SEELCT-Abfragen durchführen. Alle SELECT-Anweisungen, die wir bisher gesehen haben, sind gewöhnliche Abfragen. Darüber werden wir später sprechen.

Empfohlenes Lernen: MySQL-Video-Tutorial

Das obige ist der detaillierte Inhalt vonMySQL fasst das MVCC-Prinzip von InnoDB zusammen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:csdn.net
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage