Vorwort: Die Artikelserie „Erste Schritte mit MySQL“ ist beendet. In Zukunft werde ich mich in meinen Artikeln weiterhin auf MySQL konzentrieren und hauptsächlich die Szenarien beschreiben, die ich bei meiner jüngsten Arbeit und meinem Studium erlebt habe, oder meine eigenen Gefühle und Ideen. Die nachfolgenden Artikel sind möglicherweise nicht so kohärent, aber ich hoffe trotzdem auf Ihre Unterstützung. Kommen wir zurück zum Thema. Dieser Artikel stellt hauptsächlich den Inhalt im Zusammenhang mit langen MySQL-Transaktionen vor. Was passiert beispielsweise, wenn wir eine Transaktion starten, diese aber nicht festgeschrieben oder zurückgesetzt wurde? Wie sollten wir mit der Wartesituation bei Transaktionen umgehen? Dieser Artikel gibt Ihnen die Antwort. Hinweis: In diesem Artikel geht es nicht um die Erörterung von Transaktionsisolationsebenen und verwandten Funktionen. Stattdessen werden die mit Langzeittransaktionen verbundenen Gefahren sowie deren Überwachung und Handhabung vorgestellt. Dieser Artikel basiert auf Experimenten, die mit MySQL Version 5.7.23 und der Isolationsebene „Non-Repeatable Read“ (RR) durchgeführt wurden. 1. Was ist eine Long-Transaktion? Zunächst müssen wir wissen, was eine lange Transaktion ist. Wie der Name schon sagt, handelt es sich um eine Transaktion, die lange ausgeführt wird und für lange Zeit nicht festgeschrieben wird. Sie kann auch als große Transaktion bezeichnet werden. Diese Art von Transaktion verursacht häufig viele Blockierungen und Sperrzeitüberschreitungen, was leicht zu Master-Slave-Verzögerungen führen kann. Versuchen Sie, lange Transaktionen zu vermeiden. Im Folgenden werde ich zeigen, wie man eine Transaktion startet und eine lange Transaktion simuliert: #Angenommen, wir haben eine stu_tb-Tabelle mit der folgenden Struktur und den folgenden Daten mysql> show create table stu_tb\G *************************** 1. Reihe *************************** Tabelle: stu_tb Tabelle erstellen: CREATE TABLE `stu_tb` ( `increment_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primärschlüssel automatisch inkrementieren', `stu_id` int(11) NOT NULL KOMMENTAR 'Studenten-ID', `stu_name` varchar(20) DEFAULT NULL COMMENT 'Studentenname', `create_time` Zeitstempel NICHT NULL STANDARD CURRENT_TIMESTAMP KOMMENTAR 'Erstellungszeit', `update_time` Zeitstempel NICHT NULL STANDARD CURRENT_TIMESTAMP BEI UPDATE CURRENT_TIMESTAMP KOMMENTAR 'Änderungszeit', PRIMÄRSCHLÜSSEL (`increment_id`), EINZIGARTIGER SCHLÜSSEL `uk_stu_id` (`stu_id`) MIT BTREE ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='Test-Studententabelle' 1 Zeile im Satz (0,01 Sek.) mysql> wähle * aus stu_tb; +--------------+--------+----------+---------------------+---------------------+ | Inkrement-ID | Stu-ID | Stu-Name | Erstellungszeit | Aktualisierungszeit | +--------------+--------+----------+---------------------+---------------------+ | 1 | 1001 | von1 | 15.09.2019 14:27:34 | 15.09.2019 14:27:34 | | 2 | 1002 | dfsfd | 15.09.2019 14:27:34 | 15.09.2019 14:27:34 | | 3 | 1003 | fdgfg | 15.09.2019 14:27:34 | 15.09.2019 14:27:34 | | 4 | 1004 | sdfsdf | 15.09.2019 14:27:34 | 15.09.2019 14:27:34 | | 5 | 1005 | dsfsdg | 15.09.2019 14:27:34 | 15.09.2019 14:27:34 | | 6 | 1006 | fgd | 15.09.2019 14:27:34 | 15.09.2019 14:27:34 | | 7 | 1007 | fgds | 15.09.2019 14:27:34 | 15.09.2019 14:27:34 | | 8 | 1008 | dgfsa | 15.09.2019 14:27:34 | 15.09.2019 14:27:34 | +--------------+--------+----------+---------------------+---------------------+ 8 Zeilen im Satz (0,00 Sek.) #Öffnen Sie eine Transaktion explizit, verwenden Sie begin oder start transaction mysql> Transaktion starten; Abfrage OK, 0 Zeilen betroffen (0,00 Sek.) mysql> select * from stu_tb where stu_id = 1006 für Update; +--------------+--------+----------+---------------------+---------------------+ | Inkrement-ID | Stu-ID | Stu-Name | Erstellungszeit | Aktualisierungszeit | +--------------+--------+----------+---------------------+---------------------+ | 6 | 1006 | fgd | 15.09.2019 14:27:34 | 15.09.2019 14:27:34 | +--------------+--------+----------+---------------------+---------------------+ 1 Zeile im Satz (0,01 Sek.) #Wenn wir die vorherige Transaktion nicht rechtzeitig festschreiben, wird diese Transaktion zu einer langen Transaktion. Wenn andere Sitzungen mit diesen Daten arbeiten möchten, müssen sie weiter warten. 2. So finden Sie Long-Transaktionen Wenn wir auf ein Problem beim Warten auf eine Transaktion stoßen, müssen wir zunächst die ausgeführte Transaktion finden. Die Tabelle information_schema.INNODB_TRX enthält die Transaktionsinformationen, die derzeit in InnoDB ausgeführt werden. Diese Tabelle gibt die Startzeit der Transaktion an. Mit einer kleinen Berechnung können wir die Ausführungszeit der Transaktion ermitteln. mysql> wähle t.*,to_seconds(jetzt())-to_seconds(t.trx_started) Leerlaufzeit aus INFORMATION_SCHEMA.INNODB_TRX t \G *************************** 1. Reihe *************************** trx_id: 6168 trx_state: LÄUFT trx_started: 16.09.2019 11:08:27 trx_requested_lock_id: NULL trx_wait_started: NULL trx_gewicht: 3 trx_mysql_thread_id: 11 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 1 trx_lock_structs: 3 trx_lock_memory_bytes: 1136 trx_rows_locked: 2 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: 0 trx_ist_schreibgeschützt: 0 trx_autocommit_non_locking: 0 Leerlaufzeit: 170 Im Ergebnis wird die Leerlaufzeit berechnet. Sie stellt die Dauer der Transaktion dar. Die trx_query der Transaktion ist jedoch NUL. Das bedeutet nicht, dass die Transaktion nichts ausgeführt hat. Eine Transaktion kann mehrere SQL-Anweisungen enthalten. Wenn die SQL-Anweisung ausgeführt wird, wird sie nicht mehr angezeigt. Die aktuelle Transaktion wird ausgeführt und InnoDB weiß nicht, ob es für diese Transaktion nachfolgende SQL-Anweisungen geben wird oder wann sie festgeschrieben wird. Daher kann trx_query keine sinnvollen Informationen liefern. Was ist, wenn wir das von dieser Transaktion ausgeführte SQL sehen möchten, um zu sehen, ob wir die lange Transaktion beenden können? Wir können es in Verbindung mit anderen Systemtabellen abfragen. Die spezifische SQL-Abfrage lautet wie folgt: mysql> wähle now(),(UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(a.trx_started)) diff_sec,b.id,b.user,b.host,b.db,d.SQL_TEXT aus information_schema.innodb_trx ein innerer Join -> information_schema.PROCESSLIST b -> auf a.TRX_MYSQL_THREAD_ID=b.id und b.command = 'Sleep' -> innerer Join performance_schema.threads c ON b.id = c.PROCESSLIST_ID -> innerer Join performance_schema.events_statements_current d ON d.THREAD_ID = c.THREAD_ID; +---------------------+----------+----+------+-----------+--------+--------+-----------------------------------------------------------+ | jetzt() | diff_sec | ID | Benutzer | Host | db | SQL_TEXT | +---------------------+----------+----+------+-----------+--------+--------+-----------------------------------------------------------+ | 16.09.2019 14:06:26 | 54 | 17 | root | localhost | testdb | select * from stu_tb where stu_id = 1006 für Update | +---------------------+----------+----+------+-----------+--------+--------+-----------------------------------------------------------+ In den obigen Ergebnissen hat diff_sec dieselbe Bedeutung wie idle_time oben, also die Anzahl der Sekunden, die diese Transaktion dauert. SQL_TEXT gibt das gerade von der Transaktion ausgeführte SQL an. Die obige Anweisung kann jedoch nur das zuletzt in der Transaktion ausgeführte SQL finden. Wir wissen, dass eine Transaktion mehrere SQLs enthalten kann. Dann möchten wir abfragen, welche SQLs von dieser nicht festgeschriebenen Transaktion ausgeführt wurden. Kann diese Abfrage erfüllt werden? Die Antwort ist, dass sie auch durch Kombinieren der Systemtabelle events_statements_history erfüllt werden kann. Die folgende Anweisung fragt den gesamten von der Transaktion ausgeführten SQL-Befehl ab: mysql> wähle now(),(UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(a.trx_started)) diff_sec,b.id,b.user,b.host,b.db,d.SQL_TEXT aus information_schema.innodb_trx ein innerer Join -> information_schema.PROCESSLIST b -> auf a.TRX_MYSQL_THREAD_ID=b.id und b.command = 'Sleep' -> innerer Join performance_schema.threads c ON b.id = c.PROCESSLIST_ID -> innerer Join performance_schema.events_statements_current d ON d.THREAD_ID = c.THREAD_ID; +---------------------+----------+----+------+-----------+--------+--------+-----------------------------------------------------------+ | jetzt() | diff_sec | ID | Benutzer | Host | db | SQL_TEXT | +---------------------+----------+----+------+-----------+--------+--------+-----------------------------------------------------------+ | 16.09.2019 14:06:26 | 54 | 17 | root | localhost | testdb | select * from stu_tb where stu_id = 1006 für Update | +---------------------+----------+----+------+-----------+--------+--------+-----------------------------------------------------------+ Aus den obigen Ergebnissen können wir alle von der Transaktion ausgeführten SQL-Anweisungen von Anfang bis jetzt sehen. Nachdem wir alle relevanten Informationen der Transaktion abgefragt haben, können wir feststellen, ob die Transaktion abgebrochen werden kann, um zu vermeiden, dass andere Transaktionen beeinträchtigt werden und Wartezeiten entstehen. Lassen Sie mich das etwas näher ausführen. Lange Transaktionen führen sehr wahrscheinlich zu Blockierungen oder Deadlocks. Normalerweise können wir zuerst die Ansicht sys.innodb_lock_waits abfragen, um festzustellen, ob es eine Transaktionsblockierung gibt: #Nehmen wir an, eine Transaktion führt select * from stu_tb where stu_id = 1006 für das Update aus #Eine andere Transaktion führt das Update stu_tb aus und setzt stu_name = 'wang', wobei stu_id = 1006 mysql> wähle * aus sys.innodb_lock_waits\G *************************** 1. Reihe *************************** wait_started: 16.09.2019 14:34:32 Wartezeit: 00:00:03 Wartezeit_Sekunden: 3 gesperrte_Tabelle: `testdb`.`stu_tb` locked_index: uk_stu_id gesperrter Typ: AUFZEICHNUNG wartende_trx_id: 6178 waiting_trx_started: 16.09.2019 14:34:32 Wartezeit: 00:00:03 waiting_trx_rows_locked: 1 waiting_trx_rows_modified: 0 warte_pid: 19 waiting_query: Aktualisiere stu_tb, setze stu_name = 'wang', wobei stu_id = 1006 Wartesperren-ID: 6178:47:4:7 Wartesperrmodus: X Blockierungs-TRX-ID: 6177 Blockierungs-PID: 20 Blockierungsabfrage: NULL Sperrsperr-ID: 6177:47:4:7 Blockierungssperrmodus: X blocking_trx_started: 16.09.2019 14:18:44 Blockierung_TRX_Alter: 00:15:51 Blockierung_TRX_Zeilen_gesperrt: 2 Blockieren von TRX-Zeilen geändert: 0 sql_kill_blocking_query: KILL-ABFRAGE 20 sql_kill_blocking_connection: KILL 20 Die obigen Ergebnisse zeigen das blockierte SQL und den Sperrtyp. Noch leistungsfähiger ist, dass auch die Anweisung zum Beenden der Sitzung angegeben wird. Es wurde jedoch kein SQL gefunden, das die Sitzungsausführung blockiert. Wenn wir genauere Informationen erhalten möchten, können wir die folgende Anweisung verwenden: mysql> AUSWÄHLEN -> temporär*, -> c.SQL_Text blockierender_SQL_Text, -> p.HOST blockierender_Host -> VON -> ( -> AUSWÄHLEN -> r.trx_state beobachtet_trx_state, -> r.trx_id warte_trx_id, -> r.trx_mysql_thread_Id Wartethread, -> r.trx_query warte_abfrage, -> b.trx_state Blockierungs-TRX_State, -> b.trx_id blockierende_trx_id, -> b.trx_mysql_thread_id blockierender Thread, -> b.trx_query blockierende_Abfrage -> VON -> information_schema.innodb_lock_waits w -> INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id -> INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id -> ) tmp, -> information_schema.PROCESSLIST p, -> PERFORMANCE_SCHEMA.events_statements_current c, -> PERFORMANCE_SCHEMA.threads t -> WO -> tmp.blocking_thread = p.id -> UND t.thread_id = c.THREAD_ID -> UND t.PROCESSLIST_ID = p.id \G *************************** 1. Reihe *************************** watching_trx_state: SPERRE WARTEN wartende_trx_id: 6180 Wartethread: 19 waiting_query: Aktualisiere stu_tb, setze stu_name = 'wang', wobei stu_id = 1006 blocking_trx_state: LÄUFT Blockierungs-TRX-ID: 6177 blockierender_Thread: 20 Blockierungsabfrage: NULL blocking_sql_text: wähle * aus stu_tb, wobei stu_id = 1006 für Update blockierender_Host: lokaler Host Die obigen Ergebnisse sind klarer. Wir können die von den blockierenden und blockierten Transaktionen ausgeführten Anweisungen deutlich sehen, was uns bei der Fehlerbehebung hilft und uns hilft zu bestätigen, ob die blockierte Sitzung beendet werden kann. 3. Überwachen Sie lange Transaktionen In der Praxis müssen wir lange Transaktionen überwachen und einen Schwellenwert festlegen, beispielsweise 30 Sekunden. Transaktionen, deren Ausführung länger als 30 Sekunden dauert, sind lange Transaktionen und müssen aufgezeichnet und gemeldet werden, um das Managementpersonal an die Bearbeitung zu erinnern. Das Überwachungsskript ist unten aufgeführt. Sie können es zu Rate ziehen und nach Bedarf ändern: #!/bin/bash # ----------------------------------------------------------------------------------- # Dateiname: long_trx.sh # Beschreiben Sie: Überwachung langer Transaktionen # Revision: 1.0 # Datum: 16.09.2019 # Autor: wang /usr/local/mysql/bin/mysql -N -uroot -pxxxxxx -e "select now(),(UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(a.trx_started)) diff_sec,b.id,b.user,b.host,b.db,d.SQL_TEXT aus information_schema.innodb_trx ein innerer Join information_schema.PROCESSLIST b bei a.TRX_MYSQL_THREAD_ID=b.id und b.command = 'Sleep' Innerer Join performance_schema.threads c ON b.id = c.PROCESSLIST_ID innerer Join performance_schema.events_statements_current d ON d.THREAD_ID = c.THREAD_ID;" | während des Lesens ABCDEFGH Tun wenn [ "$C" -gt 30 ] Dann echo $(Datum +"%J-%m-%d %H:%M:%S") echo "Prozess-ID[$D] $E@$F in db[$G] halte Transaktionszeit $C SQL:$H" fi fertig >> /tmp/longtransaction.txt Zur kurzen Erklärung: -gt 30 bedeutet hier 30 Sekunden. Wenn es 30 Sekunden überschreitet, wird es als lange Transaktion betrachtet. Sie können es entsprechend den tatsächlichen Anforderungen anpassen. Fügen Sie das Skript der geplanten Aufgabe hinzu und es wird ausgeführt. Zusammenfassen: In diesem Artikel werden hauptsächlich Inhalte zu langen Transaktionen sowie die Suche nach langen Transaktionen, der Umgang mit langen Transaktionen und die Überwachung langer Transaktionen vorgestellt. Vielleicht wissen einige von Ihnen nicht viel über Transaktionen. Ich hoffe, dieser Artikel wird Ihnen hilfreich sein. Da in diesem Artikel viele Anweisungen zu Abfragetransaktionen aufgelistet sind, werden sie wie folgt zusammengefasst: # Alle laufenden Transaktionen und deren Laufzeit abfragen select t.*,to_seconds(now())-to_seconds(t.trx_started) idle_time from INFORMATION_SCHEMA.INNODB_TRX t \G # Transaktionsdetails abfragen und SQL ausführen Wählen Sie jetzt (), (UNIX_TIMESTAMP (jetzt ()) - UNIX_TIMESTAMP (a.trx_started)) diff_sec, b.id, b.user, b.host, b.db, d.SQL_TEXT aus information_schema.innodb_trx ein innerer Join information_schema.PROCESSLIST b bei a.TRX_MYSQL_THREAD_ID=b.id und b.command = 'Sleep' Innerer Join performance_schema.threads c ON b.id = c.PROCESSLIST_ID innerer Join performance_schema.events_statements_current d ON d.THREAD_ID = c.THREAD_ID; # Abfrage aller historischen SQL-Datensätze, die von der Transaktion SELECT ausgeführt wurden ps.id 'PROZESS-ID', ps.BENUTZER, ps.HOST, esh.EVENT_ID, trx.trx_started, esh.event_name 'EREIGNISNAME', esh.sql_text 'SQL', ps.Zeit AUS PERFORMANCE_SCHEMA.events_statements_history esh JOIN PERFORMANCE_SCHEMA.threads th ON esh.thread_id = th.thread_id JOIN information_schema.PROCESSLIST ps ON ps.id = th.processlist_id LINKS JOIN information_schema.innodb_trx trx ON trx.trx_mysql_thread_id = ps.id WO trx.trx_id IST NICHT NULL UND ps.USER != 'SYSTEM_USER' BESTELLEN BIS esh.EVENT_ID; # Einfache Abfrage Transaktionssperre select * from sys.innodb_lock_waits\G #Transaktionssperrdetails abfragenSELECT tmp.*, c.SQL_Text blockierender_SQL_Text, p.HOST blockierender_Host AUS ( WÄHLEN r.trx_state beobachtet_trx_state, r.trx_id warte_trx_id, r.trx_mysql_thread_Id Wartethread, r.trx_query warte_abfrage, b.trx_state Blockierender_trx_state, b.trx_id blockierende_trx_id, b.trx_mysql_thread_id blockierender Thread, b.trx_query blockierende_Abfrage AUS information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id ) tmp, information_schema.PROCESSLIST p, PERFORMANCE_SCHEMA.events_statements_current c, PERFORMANCE_SCHEMA.threads t WO tmp.blocking_thread = p.id UND t.thread_id = c.THREAD_ID UND t.PROCESSLIST_ID = p.id \G Zusammenfassen Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Lernwert für Ihr Studium oder Ihre Arbeit hat. Vielen Dank für Ihre Unterstützung von 123WORDPRESS.COM. Das könnte Sie auch interessieren:
|
<<: Statische IP-Konfigurationsmethode für die Centos8-Brücke in der virtuellen VMware-Maschine
1. Nutzung auf höchster Ebene 1. Installieren Sie...
Vor Kurzem mussten wir eine geplante Migration de...
1. Einzelne Tabellenabfrage -> Update UPDATE T...
Inhaltsverzeichnis 1. Prototyp-Beziehung 2. Proto...
Inhaltsverzeichnis Eröffnungsszene Direktes Rende...
Vorwort In der Demonstration [IE9-] ist der Farbv...
1. Grammatik Standort [=|~|~*|^~|@] /uri/ { ... }...
Schritt 1: Erstellen Sie ein Django-Projekt Öffne...
Das folgende Skript wird für die geplante Sicheru...
Der MGR unserer Bank wird Ende des Jahres eingefü...
Inhaltsverzeichnis Anwendungsszenarien: Methode 1...
In diesem Artikel wird der spezifische Code von V...
Vorwort: Partitionierung ist ein Tabellenentwurfs...
Wenn eine Spalte in einer Datentabelle einmal als...
Gruppieren und Verknüpfen sind in MySQL die beide...