1. EinleitungAls Datenbank-Enthusiast habe ich selbst einen einfachen SQL-Parser und eine Speicher-Engine geschrieben, aber ich bin damit immer noch nicht zufrieden. <<Transaktionsverarbeitung – Konzepte und Technologien>> ist zwar sehr ausführlich, kann Ihnen jedoch nur einen allgemeinen Überblick verschaffen und ist nicht bei der Arbeit mit einer echten Datenbank hilfreich. Dank cmake kann ich mit xcode MySQL auf dem Mac debuggen, sodass ich die verschiedenen Implementierungsdetails würdigen kann. (Hinweis: Die in diesem Artikel verwendete MySQL-Version ist MySQL-5.6.35) 2. MVCC (Multi-Version Concurrency Control Mechanism)Isolation kann auch als Parallelitätskontrolle, Serialisierbarkeit usw. bezeichnet werden. Wenn man über Parallelitätskontrolle spricht, denkt man zuerst an Sperren. MySQL implementiert die Serialisierbarkeit von Aktualisierungen mithilfe von zweiphasigen Sperren. Gleichzeitig wird zur Beschleunigung der Abfrageleistung der MVCC-Mechanismus (Multi Version Concurrency Control) übernommen, sodass konsistente Versionen ohne Sperren erhalten werden können. 2.1 Wiederholbares LesenMySQL implementiert Repeatable Read durch MVCC und Next-Key Lock. Die Idee von MVCC besteht darin, die Versionsänderungen von Daten aufzuzeichnen und Benutzern durch geschickte Auswahl verschiedener Datenversionen konsistente Ergebnisse zu präsentieren. Wie in der folgenden Abbildung dargestellt: In der obigen Abbildung ist die Anfangsversion von (A=50|B=50) 1. 1. Wenn Transaktion t1 A auswählt, sieht sie Version 1, d. h. A = 50 2. Transaktion t2 ändert A und B und aktualisiert die Version auf 2, d. h. A = 0, B = 100 3. Wenn Transaktion t1 B erneut auswählt, ist die angezeigte Version immer noch 1, d. h. B = 50 Dadurch wird der Einfluss der Version isoliert und A+B ergibt immer 100. 2.2 Commit lesenWenn das zuletzt festgeschriebene Ergebnis ohne Versionskontrollmechanismus gelesen wird, lautet die Isolationsebene „Read Commit“, wie in der folgenden Abbildung dargestellt: In diesem Fall müssen Sie einen Sperrmechanismus (z. B. „Auswählen zum Aktualisieren“) verwenden, um die Datensätze A und B zu sperren und so korrekte und konsistente Ergebnisse zu erhalten, wie in der folgenden Abbildung dargestellt: 2.3 Vorteile von MVCCWenn wir schreibgeschützte Vorgänge für bestimmte Daten ausführen müssen, um deren Konsistenz zu prüfen, z. B. um zu überprüfen, ob die Konten ausgerichtet sind, möchten wir keine Sperren hinzufügen, die zu großen Leistungseinbußen führen. Derzeit hat die konsistente Version von MVCC einen großen Vorteil. 3. MVCC (Implementierungsmechanismus)In diesem Abschnitt wird zunächst der Implementierungsmechanismus von MVCC erläutert. Beachten Sie, dass MVCC nur für reine Auswahl gültig ist (ausgenommen Sperrvorgänge wie Auswahl zum Aktualisieren, Sperren im Freigabemodus und Aktualisieren\Einfügen usw.). 3.1. Wählen Sie den laufenden Stapel ausLassen Sie uns zunächst den laufenden Prozess einer allgemeinen SQL-Abfrage im MySQL-Quellcode verfolgen. Die SQL lautet (select * from test); Der laufende Stapel ist:
Da die Standardisolationsstufe von MySQL repeatable_read (RR) ist, ist read_record überladen als
Werfen wir einen Blick in diese Funktion: bool lock_clust_rec_cons_read_sees(const rec_t* rec /*eine von innodb gescannte Zeile*/,...){ ... // Holen Sie sich die zuletzt geänderte Version trx_id (Transaktions-ID) aus der aktuell gescannten Zeile trx_id = row_get_rec_trx_id(rec, index, offsets); // Bestimmen Sie den Zeilen-Snapshot, der durch die Parameter angezeigt wird (konsistente Snapshot-Ansicht und Transaktions-ID) return(read_view_sees_trx_id(view, trx_id)); } 3.2. Erstellungsprozess von read_viewKonzentrieren wir uns zunächst auf den Erstellungsprozess der Konsistenzansicht. Schauen wir uns zunächst die read_view-Struktur an: Struktur read_view_t{ // Da die Reihenfolge umgekehrt ist, sind „low“ und „up“ vertauscht. // Sie können die Hochwassermarke der aktuellen Zeilenversion sehen, und >= low_limit_id ist nicht sichtbar. trx_id_t low_limit_id; // Sie können die Niedrigwassermarke der aktuellen Zeilenversion sehen, <up_limit_id ist zu sehen trx_id_t up_limit_id; // Die Anzahl der aktuell aktiven Transaktionen (d. h. nicht festgeschriebene Transaktionen) ulint n_trx_ids; // Holen Sie sich das Array der derzeit aktiven Transaktions-IDs in umgekehrter Reihenfolge // Seine up_limit_id<tx_id<low_limit_id trx_id_t* trx_ids; //Erstellen Sie die Transaktions-ID der aktuellen Ansicht trx_id_t Ersteller_trx_id; //Konsistenzansichtsliste im Transaktionssystem UT_LIST_NODE_T(read_view_t) view_list; }; Durch das Debuggen wird dann festgestellt, dass die Erstellung der read_view-Struktur auch im obigen rr_sequential ausgeführt wird, und der Aufrufstapel wird fortgesetzt:
Schauen wir uns einen Zweig in row_search_for_mysql an: Zeilensuche nach MySQL: // Die Konsistenzansicht wird nur erstellt, wenn der sperrenfreie Modus ausgewählt ist, sonst wenn (prebuilt->select_lock_type == LOCK_NONE) { // Eine Konsistenzansicht erstellen trx_assign_read_view(trx); vorgefertigt->sql_stat_start = FALSE; } Der obige Kommentar ist der Grund, warum die Auswahl zum Aktualisieren (im Freigabemodell) nicht MVCC folgt. Lassen Sie uns die Funktion trx_assign_read_view weiter analysieren:
Nun sind wir endlich beim Hauptstadium der Erstellung von read_view angelangt. Der Hauptprozess ist in der folgenden Abbildung dargestellt: Der Code-Prozess ist: statisches Lese-Ansicht_t* Lese-Ansicht_jetzt_öffnen_niedrig(trx_id_t cr_trx_id,mem_heap_t* Heap) { read_view_t* Ansicht; // Im aktuellen Transaktionssystem wird max_trx_id (d. h. trx_id, die nicht zugewiesen wurde) auf low_limit_no gesetzt Ansicht -> Untergrenze_Nr. = trx_sys -> max_trx_id; Ansicht->Untergrenzen-ID = Ansicht->Untergrenzen-Nr. // Der CreateView-Konstruktor entfernt nicht aktuelle Transaktionen und Transaktionen, die im Speicher festgeschrieben wurden, d. h. die Beurteilungsbedingung ist // trx->id != m_view->creator_trx_id&& !trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY) // und fügt sie dann der aktuellen Ansichtsliste hinzu ut_list_map(trx_sys->rw_trx_list, &trx_t::trx_list, CreateView(view)); wenn (Ansicht->n_trx_ids > 0) { //Setzen Sie die Mindest-ID im aktuellen Transaktionssystem auf up_limit_id, da diese in umgekehrter Reihenfolge vorliegt: view->up_limit_id = view->trx_ids[view->n_trx_ids - 1]; } anders { // Wenn außer der aktuellen Transaktion keine aktive Transaktion vorhanden ist, setzen Sie sie auf low_limit_id Ansicht->Up_Limit_ID = Ansicht->Lokales_Limit_ID; } // Ignoriere die Löschtransaktion. Beim Löschen ist die aktuelle Transaktions-ID 0 wenn (cr_trx_id > 0) { lesen_ansicht_hinzufügen(ansicht); } //Gibt die konsistente Ansicht zurück return(view); } 3.3. Sichtbarkeit der ZeilenversionAus den obigen lock_clust_rec_cons_read_sees können wir erkennen, dass die Sichtbarkeit der Zeilenversion durch die Funktion read_view_sees_trx_id bestimmt wird: /****************************************************************************//** Überprüft, ob eine Lese-Ansicht die angegebene Transaktion sieht. @return true wenn sieht */ UNIV_INLINE bool lesen_anzeigen_sieht_trx_id( /*====================*/ const read_view_t* Ansicht, /*!< in: Ansicht lesen */ trx_id_t trx_id) /*!< in: trx-ID */ { wenn (trx_id < Ansicht->up_limit_id) { Rückkehr (wahr); } sonst wenn (trx_id >= view->low_limit_id) { Rückkehr (falsch); } anders { ulint niedriger = 0; ulint oben = Ansicht->n_trx_ids - 1; ut_a(Ansicht->n_trx_ids > 0); Tun { ulint mid = (unterer + oberer) >> 1; trx_id_t mid_id = Ansicht->trx_ids[mid]; wenn (mid_id == trx_id) { Rückkehr(FALSCH); } sonst wenn (mid_id < trx_id) { wenn (Mitte > 0) { oben = Mitte - 1; } anders { brechen; } } anders { unten = Mitte + 1; } } während (unterer <= oberer); } Rückkehr (wahr); } Tatsächlich handelt es sich bei der obigen Funktion um eine binäre Suche. read_view speichert tatsächlich alle Transaktions-IDs der aktuell aktiven Transaktion. Wenn die Transaktions-ID, die der Änderung der aktuellen Zeilenversion entspricht, nicht in der aktuell aktiven Transaktion enthalten ist, wird true zurückgegeben, was bedeutet, dass die aktuelle Version sichtbar ist, andernfalls ist sie unsichtbar, wie in der folgenden Abbildung dargestellt. Nach der Rückgabe von lock_clust_rec_cons_read_sees oben: wenn (UNIV_LIKELY(srv_force_recovery < 5) && !lock_clust_rec_cons_read_sees( aufzeichnen, indexieren, offsets, trx->read_view)){ // Derzeit wird die Situation bearbeitet, in der die aktuelle Version nicht sichtbar ist. // Verwenden Sie Undolog, um zu einer konsistenten sichtbaren Version zurückzukehren. err = row_sel_build_prev_vers_for_mysql( trx->Ansicht lesen, Clusterindex, vorgefertigt, rec, &offsets, &heap, &old_vers, &mtr); } anders{ // Sichtbar, dann zurück } 3.4. Undolog-Suchvorgang für sichtbare VersionenLassen Sie uns nun die Funktion row_sel_build_prev_vers_for_mysql untersuchen:
Hauptsächlich wird die Methode row_ver_build_for_consistent_read aufgerufen, um die sichtbare Version zurückzugeben: dberr_t row_vers_build_for_consistent_read(...) { ...... für(;;){ err = trx_undo_prev_version_build(rec, mtr,version,index,*offsets, heap,&prev_version); ...... trx_id = row_get_rec_trx_id(vorherige_Version, Index, *Offsets); // Wenn die aktuelle Zeilenversion der konsistenten Ansicht entspricht, returniere if (read_view_sees_trx_id(view, trx_id)) { ...... brechen; } // Wenn die aktuelle Zeilenversion nicht übereinstimmt, gehe weiter zurück zur vorherigen Version (kehre zur For-Schleife zurück) Version = vorherige Version; } ...... } Der gesamte Vorgang ist in der folgenden Abbildung dargestellt: Die Wiederherstellung der entsprechenden Version von Zeilendatensätzen durch Undolog ist ein komplizierter Vorgang. Aus Platzgründen wird er hier weggelassen. 3.5. Besprechen Sie, wann read_view erstellt werden sollIm Code von row_search_for_mysql, der eine konsistente Ansicht erstellt // Wählt nur im Nicht-Sperrmodus aus, erstellt konsistente Ansichten, sonst wenn (prebuilt->select_lock_type == LOCK_NONE) { // Konsistente Ansichten erstellen trx_assign_read_view(trx); vorgefertigt->sql_stat_start = FALSE; } Es gibt einen solchen Code in trx_assign_read_view // Eine konsistente Ansicht wird nur einmal pro Transaktion erstellt, wenn (!trx->read_view) { trx->read_view = read_view_jetzt_öffnen( trx->id, trx->global_read_view_heap); trx->global_read_view = trx->read_view; } Durch die Kombination dieser beiden Codeteile wird in einer Transaktion daher nur dann eine konsistente Ansicht erstellt, wenn die Auswahl zum ersten Mal ausgeführt wird (ohne Sperren), wie in der folgenden Abbildung dargestellt: Der Autor hat ein solches Szenario konstruiert und simuliert und es ist tatsächlich wahr. 4. Einige Phänomene, die durch die gleichzeitige Wirkung von MVCC und Sperren verursacht werdenMySQL verwendet MVCC und Zweiphasensperre (2PL), um Leistung und Konsistenz auszugleichen. Da MySQL jedoch nur bei der Auswahl eine konsistente Ansicht erstellt und dies bei Sperrvorgängen wie der Aktualisierung nicht tut, treten einige seltsame Phänomene auf. Wie in der folgenden Abbildung dargestellt: Wenn man versteht, dass update nicht der konsistenten Ansicht (read_view) folgt, select jedoch der konsistenten Ansicht (read_view) folgt, lässt sich dieses Phänomen gut erklären. V. FazitMySQL verwendet viele komplexe Mechanismen zum Leistungsausgleich und ACID, 2PL (Two-Phase Locking) und MVCC sind typische Beispiele für seine Implementierung. Glücklicherweise ist das Debuggen über IDEs wie Xcode praktisch, sodass die Implementierung verschiedener Mechanismen sehr genau und bequem verfolgt werden kann. Ich hoffe, dass dieser Artikel Lesern helfen kann, die gerne MySQL-Quellcode studieren. Oben finden Sie eine ausführliche Erläuterung des Quellcodes des MySQL-Mehrversions-Parallelitätskontrollmechanismus (MVCC). Weitere Informationen zum MySQL-Parallelitätskontrollmechanismus MVCC finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM! Das könnte Sie auch interessieren:
|
<<: Zusammenfassung zur Positionierung in CSS
>>: Detaillierte Erklärung des Ref-Attributs von Vue
Wenn wir einem Rechteck oder einer anderen Form, ...
Hintergrund In der Gruppe werden einige Studieren...
Code kopieren Der Code lautet wie folgt: <styl...
Umgebung: init_worker_by_lua, set_by_lua, rewrite...
Inhaltsverzeichnis 01 Einführung in GTID 02 Wie G...
1. Melden Sie sich bei der MySQL-Datenbank an mys...
Aufgrund Ihrer Unternehmensstandards gestatten Si...
Hier sind 10 HTML-Tags, die zu wenig verwendet od...
<br />Der häufigste Fehler vieler Website-De...
Vorwort Als ich heute ein Feedback-Formular für e...
Zusätzlich zu den B-Tree-Indizes bietet MySQL auc...
Ressourcenzusammenführung und -komprimierung für ...
Inhaltsverzeichnis Vorwort Was soll verwendet wer...
Inhaltsverzeichnis 1. JS-Objekt DOM –1, Funktion ...
Bei der Entwicklung eines Projekts stößt man häuf...