Eine kurze Erläuterung der Manifestation und Wertauswahlmethode von innodb_autoinc_lock_mode

Eine kurze Erläuterung der Manifestation und Wertauswahlmethode von innodb_autoinc_lock_mode

Voraussetzung: Percona 5.6 Version, Transaktionsisolationsebene ist RR

mysql> zeigen erstellen Tabelle test_autoinc_lock\G
*************************** 1. Reihe ***************************
    Tabelle: test_autoinc_lock
Tabelle erstellen: CREATE TABLE `test_autoinc_lock` (
 `id` int(11) NICHT NULL AUTO_INCREMENT,
 `a` int(11) DEFAULT NULL,
 Primärschlüssel (`id`),
 SCHLÜSSEL `idx_a` (`a`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8

1 Zeile im Satz (0,00 Sek.)
mysql> wähle * aus test_autoinc_lock;
+----+------+
| Ich würde | ein |
+----+------+
| 1 | 1 |
| 12 | 2 |
| 2 | 3 |
| 3 | 5 |
| 4 | 7 |
| 5 | 7 |
| 6 | 9 |
| 7 | 10 |
+----+------+
8 Zeilen im Satz (0,00 Sek.)

Bedingung 1 innodb_autoinc_lock_mode ist auf 0 gesetzt

Sitzung1
 begin;delete from test_autoinc_lock where a>7;//session2 wird zu diesem Zeitpunkt nicht übermittelt
mysql> insert into test_autoinc_lock(a) values(100); //Gap-Sperre vorhanden, und die Sperre wartet auf Sitzung 3
mysql> insert into test_autoinc_lock(a) values(2); //Dies ist auch im Wartezustand. Theoretisch ist dies nicht der Sperrbereich der Lückensperre, also worauf wartet es? session4
mysql> wähle * aus information_schema.innodb_trx\G
*************************** 1. Reihe ***************************
          trx_id: 2317
         trx_state: SPERRE WARTEN
        trx_started: 31.10.2016 19:28:05
   trx_requested_lock_id: 2317:20
     trx_wait_started: 31.10.2016 19:28:05
        trx_gewicht: 1
    trx_mysql_thread_id: 9
         trx_query: in test_autoinc_lock(a) Werte(2) einfügen
    trx_operation_state: Auto-Inc-Sperre festlegen
     trx_tables_in_use: 1
     trx_tables_locked: 1
     trx_lock_structs: 1
   trx_lock_memory_bytes: 360
      trx_rows_locked: 0
     trx_rows_modified: 0
  trx_concurrency_tickets: 0
    trx_isolation_level: WIEDERHOLBARES LESEN
     trx_unique_checks: 1
  trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 10000
     trx_ist_schreibgeschützt: 0
trx_autocommit_non_locking: 0

Überprüfen Sie zu diesem Zeitpunkt, dass Sitzung 3 auf die Auto-Inkrement-Sperre wartet und sich im Status der Einstellung der Auto-Inkrement-Sperre befunden hat.

Sitzung2

FEHLER 1205 (HY000): Wartezeit für Sperre überschritten; versuchen Sie, die Transaktion neu zu starten.

Zu diesem Zeitpunkt wird Sitzung 3 gesperrt und wartet auf das Timeout, um beendet zu werden.

Sitzung3

Schauen Sie sich nun Sitzung 3 an und Sie können sehen, dass die Einfügung abgeschlossen ist.

mysql> wähle * aus test_autoinc_lock;
+----+------+
| Ich würde | ein |
+----+------+
| 1 | 1 |
| 12 | 2 |
| 13 | 2 |
| 2 | 3 |
| 3 | 5 |
| 4 | 7 |
| 5 | 7 |
| 6 | 9 |
| 7 | 10 |
+----+------+
9 Zeilen im Set (0,00 Sek.) //Beachten Sie, dass der maximale Autoinkrementwert zu diesem Zeitpunkt 13 beträgt, was dem vorherigen maximalen Autoinkrementwert + 1 entspricht. Mit anderen Worten, Sitzung2 hat später die erwartete Autoinkrement-ID freigegeben und 13 Sitzung3 überlassen. Die Anwendung von Autoinkrement-ID-Werten ist vollständig seriell.

Fazit: Wenn innodb_autoinc_lock_mode 0 ist, wird es offiziell als traditionell bezeichnet

Ebene: Die Autoinkrementsperre befindet sich auf der Ebene der Tabellensperre und muss warten, bis das aktuelle SQL ausgeführt oder zurückgesetzt wird, bevor sie freigegeben wird. Auf diese Weise ist es denkbar, dass bei hoher Parallelität der Wettbewerb um die Autoinkrementsperre relativ groß ist.

Bedingung 2: innodb_autoinc_lock_mode ist auf 1 gesetzt

Sitzung1
mysql> beginnen;
Abfrage OK, 0 Zeilen betroffen (0,00 Sek.)


mysql> löschen aus test_autoinc_lock, wobei a>7;
Abfrage OK, 2 Zeilen betroffen (0,00 Sek.)
mysql> wähle * aus test_autoinc_lock;
+----+------+
| Ich würde | ein |
+----+------+
| 1 | 1 |
| 12 | 2 |
| 13 | 2 |
| 2 | 3 |
| 3 | 5 |
| 4 | 7 |
| 5 | 7 |
| 6 | 9 |
| 7 | 10 |
+----+------+
9 Zeilen im Satz (0,00 Sek.) //Beachten Sie, dass die maximale automatische Inkrementierung zu diesem Zeitpunkt 13 beträgt


Sitzung2
mysql> insert into test_autoinc_lock(a) values(100); //Die gleiche Lückensperre existiert und die Sperre wartet auf Sitzung 3
mysql> in test_autoinc_lock(a) Werte(5) einfügen;
Abfrage OK, 1 Zeile betroffen (0,00 Sek.)


mysql> wähle * aus test_autoinc_lock;
+----+------+
| Ich würde | ein |
+----+------+
| 1 | 1 |
| 12 | 2 |
| 13 | 2 |
| 2 | 3 |
| 3 | 5 |
| 15 | 5 |
| 4 | 7 |
| 5 | 7 |
| 6 | 9 |
| 7 | 10 |
+----+------+
10 Zeilen im Set (0,00 Sek.) //session3 wird direkt abgeschlossen. Beachten Sie, dass der eingefügte Auto-Increment-ID-Wert 15 ist, was bedeutet, dass die 14, die Session2 zugewiesen werden sollte, übersprungen wird. Sie können sehen, dass der Auto-Increment-ID-Wert sofort Session3 zugewiesen wird, ohne dass Sie warten müssen, bis Session2 die Ausführung abgeschlossen hat.

Fazit: Wenn innodb_autoinc_lock_mode 1 ist, wird es offiziell als aufeinanderfolgend bezeichnet

Auf dieser Ebene kann, wenn es sich um ein einzelnes Insert-SQL handelt, die Sperre sofort erworben und freigegeben werden, ohne auf die Ausführung des aktuellen SQL warten zu müssen (es sei denn, eine Sitzung hat die Auto-Increment-Sperre bereits in anderen Transaktionen erworben). Darüber hinaus handelt es sich auch dann noch um eine Sperre auf Tabellenebene, wenn es sich bei dem SQL um eine Art Batch-Insert-SQL handelt, wie etwa „insert into ...select ...“, „load data“, „replace ..select ...“. Dies kann so verstanden werden, dass man auf die Ausführung des aktuellen SQL warten muss, bevor man es freigeben kann.

Man kann davon ausgehen, dass es sich bei einem Wert von 1 um eine relativ leichte Sperre handelt und die Replikation nicht beeinträchtigt wird. Der einzige Nachteil besteht darin, dass der generierte Autoinkrementwert möglicherweise nicht vollständig kontinuierlich ist (aber ich persönlich denke, dass dies oft nicht sehr wichtig ist und es nicht erforderlich ist, die Anzahl der Zeilen basierend auf dem Autoinkrement-ID-Wert zu zählen).

Bedingung 3: innodb_autoinc_lock_mode ist auf 2 gesetzt

Lassen Sie mich zunächst die Schlussfolgerung ziehen: Wenn innodb_autoinc_lock_mode auf 2 gesetzt ist, können alle SQL-Anweisungen vom Typ „Insert“ sofort Sperren erwerben und freigeben, was am effizientesten ist. Es wird jedoch ein neues Problem eingeführt: Wenn binlog_format eine Anweisung ist, kann die Sicherheit der Replikation nicht garantiert werden, da Batch-Einfügungen, wie z. B. Einfügen ..select...-Anweisungen, in diesem Fall auch sofort eine große Anzahl von automatisch inkrementierten ID-Werten erhalten können, ohne die gesamte Tabelle zu sperren. Der Slave wird beim Wiedergeben dieses SQL zwangsläufig verwirrt. Führen wir einen Test durch, um zu überprüfen, ob die Replikation nicht sicher ist.

Master-Sitzung1
mysql> Variablen wie „%binlog_for%“ anzeigen;
+---------------+-----------+
| Variablenname | Wert |
+---------------+-----------+
| binlog_format | ANWEISUNG |
+---------------+-----------+
1 Zeile im Satz (0,00 Sek.)
mysql> einfügen in test_autoinc_lock(a) select * from test_auto;
Abfrage OK, 8388608 Zeilen betroffen, 1 Warnung (29,85 Sek.)
Datensätze: 8388608 Duplikate: 0 Warnungen: 1


Master-Sitzung2 (beachten Sie, dass Sitzung2 ausgeführt wird, bevor Sitzung1 abgeschlossen ist)
mysql> in test_autoinc_lock(a) Werte(2) einfügen;
Abfrage OK, 1 Zeile betroffen (0,01 Sek.)
mysql> wähle * aus test_autoinc_lock, wobei a=2;
+---------+------+
| Ich würde | ein |
+---------+------+
| 1376236 | 2 |
+---------+------+
1 Zeile im Satz (0,00 Sek.)


Slave-Sitzung1 (zu diesem Zeitpunkt sind 1376236 Primärschlüsselkonflikte zu sehen)
mysql> Slave-Status anzeigen\G
*************************** 1. Reihe ***************************
        Slave_IO_State: Wartet darauf, dass der Master ein Ereignis sendet
         Master_Host: 10.9.73.139
         Master_Benutzer: ucloudbackup
         Master_Port: 3306
        Verbindungswiederholung: 60
       Master_Log_File: mysql-bin.000006
     Read_Master_Log_Pos: 75823243
        Relay-Logdatei:mysql-relay.000002
        Relay_Log_Pos: 541
    Relay_Master_Log_File: mysql-bin.000006
       Slave_IO_Running: Ja
      Slave_SQL_Running: Nein
       Replicate_Do_DB: 
     Replikat_Ignorieren_DB: 
      Tabelle_replizieren: 
    Tabelle_Ignorieren_replizieren: 
   Wild_Do_Tabelle replizieren: 
 Tabelle_Wild_Ignore_replizieren: 
          Letzte_Fehlernummer: 1062
          Last_Error: Fehler „Doppelter Eintrag „1376236“ für Schlüssel „PRIMARY“ bei Abfrage. Standarddatenbank: „test“. Abfrage: „insert into test_autoinc_lock(a) select * from test_auto“
         Skip_Counter: 0
     Exec_Master_Log_Pos: 75822971

Wir können die Ursache des Problems leicht finden, indem wir das Binärprotokoll der Master-Datenbank analysieren. Als der erste Batch-Eintrag nicht abgeschlossen wurde, erhielt der zweite einfache Eintrag eine Sperre mit einem Auto-Increment-ID-Wert von 1376236. Beim Schreiben in die Master-Datenbank gibt es zu diesem Zeitpunkt kein Problem, aber wenn es in der Slave-Datenbank widergespiegelt wird, tritt zwangsläufig ein Primärschlüsselkonflikt auf, da es sich um eine anweisungsbasierte Replikation handelt.

SETZEN SIE INSERT_ID=1376236/*!*/;
#161031 21:44:31 Server-ID 168380811 End-Log-Pos 75822940 CRC32 0x65797f1c Abfrage Thread-ID = 20 Exec-Zeit = 0 Fehlercode = 0
verwende „test“/*!*/;
ZEITSTEMPEL FESTLEGEN=1477921471/*!*/;
in test_autoinc_lock(a) Werte einfügen(2)
/*!*/;
# bei 75822940
#161031 21:44:31 Server-ID 168380811 end_log_pos 75822971 CRC32 0xbb91449d Xid = 274
BEGEHEN /*!*/;
# bei 75822971
#161031 21:44:26 Server-ID 168380811 End-Log-Pos 75823050 CRC32 0xa297b57b Abfrage Thread-ID = 57 Exec-Zeit = 30 Fehlercode = 0
ZEITSTEMPEL EINSTELLEN=1477921466/*!*/;
BEGINNEN
/*!*/;
# bei 75823050
# bei 75823082
#161031 21:44:26 Server-ID 168380811 end_log_pos 75823082 CRC32 0xa5aa31a1 Intvar
SETZEN SIE INSERT_ID=1/*!*/;
#161031 21:44:26 Server-ID 168380811 End-Log-Pos 75823212 CRC32 0x470282ba Abfrage Thread-ID = 57 Exec-Zeit = 30 Fehlercode = 0
ZEITSTEMPEL EINSTELLEN=1477921466/*!*/;
in test_autoinc_lock(a) einfügen, * aus test_auto auswählen

Zusammenfassen:

1 Beim Kopieren von InnoDB-Zeilen können Sie innodb_autoinc_lock_mode auf 2 setzen, wodurch die Parallelität der Tabelle in allen Einfügesituationen maximiert wird.

2 Beim Replizieren von InnoDB-Anweisungen können Sie innodb_autoinc_lock_mode auf 1 setzen, um die Replikationssicherheit zu gewährleisten und gleichzeitig maximale Parallelität für einfache Einfügeanweisungen zu erreichen.

3 Im Fall der MyISAM-Engine ist das Festlegen des Parameters innodb_autoinc_lock_mode ungültig (Test ausgelassen), unabhängig davon, welche Art von automatisch inkrementeller ID-Sperre eine Sperre auf Tabellenebene ist.

4 Tatsächlich erwähnte der Fragesteller, dass bei Verwendung des Auto-Increment-ID-Werts als Primärschlüssel unter der InnoDB-Engine die Einfügegeschwindigkeit im Vergleich zu UUID oder einem benutzerdefinierten Primärschlüssel verbessert werden kann, da InnoDB ein Primärschlüssel-Clusterindex ist und auf den tatsächlichen Primärschlüsselwert in der Reihenfolge des Primärschlüssels zugegriffen werden muss. Dann erfolgt die Auto-Increment-ID selbst in aufsteigender Reihenfolge, sodass beim Einfügen von Daten die darunterliegende Ebene keine zusätzlichen Sortiervorgänge durchführen muss und die Anzahl der Indexseitenaufteilungen reduziert wird, wodurch die Einfügegeschwindigkeit erheblich erhöht wird (es sei denn, andere Lösungen können auch sicherstellen, dass der Primärschlüssel vollständig automatisch inkrementiert wird).

Die obige kurze Diskussion über die Manifestation und die Referenzmethode zur Wertauswahl von innodb_autoinc_lock_mode ist der gesamte Inhalt, den der Editor mit Ihnen teilt. Ich hoffe, er kann Ihnen als Referenz dienen. Ich hoffe auch, dass Sie 123WORDPRESS.COM unterstützen.

<<:  Detaillierte Erläuterung mehrerer Möglichkeiten zum Schreiben privater Variablen der ES6-Implementierungsklasse

>>:  Anfangseinstellungen nach der Installation von Ubuntu 16 in der Entwicklungsumgebung

Artikel empfehlen

Lernprogramm zur Verwendung des WeChat-Applets WXS

Was ist wxs? wxs (WeiXin Script) ist eine Skripts...

Beispiel für die Implementierung eines globalen Wasserzeichens in Vue

Inhaltsverzeichnis 1. Erstellen Sie eine Wasserze...

MySQL 5.7.20 Green Edition Installation Detailliertes grafisches Tutorial

Lassen Sie uns zunächst verstehen, was MySQL ist....

Natives JS zur Implementierung der Paging-Klicksteuerung

Dies ist eine Interviewfrage, die die Verwendung ...

Document Object Model (DOM) in JavaScript

Inhaltsverzeichnis 1. Was ist DOM 2. Elemente aus...

Wann sollte eine Website Anzeigen schalten?

Als ich vor kurzem mit einem Internet-Veteranen ü...

Analyse der HTTP-Dienstschritte auf einer virtuellen VMware-Maschine

1. Verwenden Sie xshell, um eine Verbindung mit d...

Vue3 kapselt die Lupeneffektkomponente der Jingdong-Produktdetailseite

In diesem Artikel wird der spezifische Code der V...

CentOS 7.5 stellt Varnish-Cache-Serverfunktion bereit

1. Einführung in Varnish Varnish ist ein leistung...

js canvas realisiert kreisförmige Wasseranimation

In diesem Artikelbeispiel wird der spezifische Co...

jQuery zum Erreichen des Sperrfeuereffekts

In diesem Artikel wird der spezifische Code von j...

JavaScript zur Implementierung eines einfachen Einkaufsformulars

In diesem Artikel wird der spezifische JavaScript...

Vollständige Schritte zur Deinstallation der MySQL-Datenbank

Der Vorgang zur vollständigen Deinstallation der ...

So betreiben Sie eine MySQL-Datenbank mit dem ORM-Modell-Framework

Was ist ORM? ORM steht für Object Relational Mapp...