Vor langer Zeit habe ich einen Blogbeitrag mit dem Titel „So finden Sie nicht festgeschriebene Transaktionsinformationen in MySQL“ zusammengefasst. Nun scheinen viele der Wissenspunkte oder Standpunkte in diesem Artikel etwas oberflächlich oder nicht tief genug zu sein, und sogar einige der Schlussfolgerungen sind falsch. Lassen Sie uns dieses Thema noch einmal aufgreifen. Lassen Sie es uns also mit dem vorherigen Beispiel einführen. --Bereiten Sie Daten für die Testumgebung vor (die experimentelle Umgebung ist MySQL 8.0.18 Community Edition) mysql> Tabelle erstellen kkk(id int , name varchar(12)); Abfrage OK, 0 Zeilen betroffen (0,34 Sek.) mysql> in kkk-Werte einfügen (1, „Kerry“); Abfrage OK, 1 Zeile betroffen (0,01 Sek.) mysql> in kkk-Werte einfügen (2, „Jerry“); Abfrage OK, 1 Zeile betroffen (0,00 Sek.) mysql> in kkk-Werte einfügen (3, „ken“); Abfrage OK, 1 Zeile betroffen (0,00 Sek.) MySQL> mysql> Tabelle erstellen t (a varchar (10)); Abfrage OK, 0 Zeilen betroffen (0,47 Sek.) mysql> in t-Werte einfügen('Test'); Abfrage OK, 1 Zeile betroffen (0,00 Sek.) Führen Sie das folgende SQL in einem Sitzungsfenster aus (Verbindungs-ID=38) mysql> wähle connection_id() von dual; +-----------------+ | Verbindungs-ID() | +-----------------+ | 38 | +-----------------+ 1 Zeile im Satz (0,00 Sek.) mysql> setze Sitzungs-Autocommit=0; Abfrage OK, 0 Zeilen betroffen (0,00 Sek.) mysql> löschen aus kkk, wo ID =1; Abfrage OK, 1 Zeile betroffen (0,00 Sek.) MySQL> Führen Sie in einem anderen Sitzungsfenster (Verbindungs-ID=39) den folgenden SQL-Befehl aus. mysql> AUSWÄHLEN t.trx_mysql_thread_id -> ,t.trx_id -> ,t.trx_state -> ,t.trx_tables_in_use -> ,t.trx_tables_locked -> ,t.trx_query -> ,t.trx_rows_locked -> ,t.trx_rows_modifiziert -> ,t.trx_lock_structs -> ,t.trx_started -> ,t.trx_isolation_level -> ,p.Zeit -> ,p.Benutzer -> ,p.host -> ,p.db -> ,p.Befehl -> VON information_schema.innodb_trx t -> INNER JOIN information_schema.prozessliste p -> EIN t.trx_mysql_thread_id = p.id -> WO t.trx_state = "LÄUFT" -> UND p.Zeit > 4 -> UND p.command = 'Schlaf'\G *************************** 1. Reihe *************************** trx_mysql_thread_id: 38 trx_id: 7981581 trx_state: LÄUFT trx_tables_in_use: 0 trx_tables_locked: 1 trx_query: NULL trx_rows_locked: 4 trx_rows_modified: 1 Anzahl der Lockstrukturen: 2 trx_started: 2020-12-03 15:39:37 trx_isolation_level: WIEDERHOLBARES LESEN Zeit: 23 Benutzer: root Host: lokaler Host db: MeineDB Befehl: Schlafen 1 Zeile im Satz (0,00 Sek.) Obwohl das obige SQL das von der Transaktion ausgeführte SQL nicht finden kann, kann das letzte von der nicht festgeschriebenen Transaktion in MySQL ausgeführte SQL tatsächlich genau durch das folgende Skript gefunden werden. Wie unten dargestellt: Wählen Sie t.trx_mysql_thread_id AS Verbindungs-ID aus. ,t.trx_id AS trx_id ,t.trx_state AS trx_state ,t.trx_started AS trx_started ,TIMESTAMPDIFF(SEKUNDE,t.trx_started, jetzt()) AS "trx_run_time(s)" ,t.trx_requested_lock_id AS trx_requested_lock_id ,t.trx_operation_state AS trx_operation_state ,t.trx_tables_in_use AS trx_tables_in_use ,t.trx_tables_locked AS trx_tables_locked ,t.trx_rows_locked AS trx_rows_locked ,t.trx_isolation_level AS trx_isolation_level ,t.trx_ist_schreibgeschützt AS trx_ist_schreibgeschützt ,t.trx_autocommit_non_locking AS trx_autocommit_non_locking ,e.Ereignisname AS Ereignisname ,e.timer_wait / 1000000000000 AS timer_wait ,e.sql_text VON information_schema.innodb_trx t, performance_schema.events_statements_current e, performance_schema.threads c WO t.trx_mysql_thread_id = c.processlist_id UND e.thread_id = c.thread_id\G; Wie im folgenden Screenshot gezeigt: Führen Sie weiterhin das folgende SQL im Sitzungsfenster aus (Verbindungs-ID=38): „select * from t;“. Wie unten gezeigt mysql> setze Sitzungs-Autocommit=0; Abfrage OK, 0 Zeilen betroffen (0,01 Sek.) mysql> löschen aus kkk, wo ID =1; Abfrage OK, 1 Zeile betroffen (0,00 Sek.) mysql> wähle * aus t; +------+ | ein | +------+ | Prüfung | +------+ 1 Zeile im Satz (0,00 Sek.) MySQL> Führen Sie die folgende SQL-Anweisung im Sitzungsfenster weiter aus (Verbindungs-ID = 39). Sie werden feststellen, dass die erfasste SQL-Anweisung die letzte von der Transaktion ausgeführte SQL-Anweisung ist: „select * from t“. mysql> SELECT t.trx_mysql_thread_id AS Verbindungs-ID -> ,t.trx_id AS trx_id -> ,t.trx_state AS trx_state -> ,t.trx_started AS trx_started -> ,TIMESTAMPDIFF(SEKUNDE,t.trx_started, jetzt()) AS "trx_run_time(s)" -> ,t.trx_requested_lock_id AS trx_requested_lock_id -> ,t.trx_operation_state AS trx_operation_state -> ,t.trx_tables_in_use AS trx_tables_in_use -> ,t.trx_tables_locked AS trx_tables_locked -> ,t.trx_rows_locked AS trx_rows_locked -> ,t.trx_isolation_level AS trx_isolation_level -> ,t.trx_ist_schreibgeschützt AS trx_ist_schreibgeschützt -> ,t.trx_autocommit_non_locking AS trx_autocommit_non_locking -> ,e.Ereignisname AS Ereignisname -> ,e.timer_wait / 1000000000000 AS timer_wait -> ,e.sql_text -> VON information_schema.innodb_trx t, -> performance_schema.events_statements_current e, -> performance_schema.threads c -> WO t.trx_mysql_thread_id = c.processlist_id -> UND e.thread_id = c.thread_id\G; *************************** 1. Reihe *************************** Verbindungs-ID: 38 trx_id: 7981581 trx_state: LÄUFT trx_started: 2020-12-03 15:39:37 trx_run_time(s): 237 trx_requested_lock_id: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 1 trx_rows_locked: 4 trx_isolation_level: WIEDERHOLBARES LESEN trx_ist_schreibgeschützt: 0 trx_autocommit_non_locking: 0 Ereignisname: Anweisung/SQL/Auswahl timer_wait: 0,0002 sql_text: wähle * aus t 1 Zeile im Satz (0,00 Sek.) FEHLER: Keine Abfrage angegeben Das heißt, das obige SQL kann nur die letzte von der nicht festgeschriebenen Transaktion ausgeführte SQL-Anweisung abrufen. In der Produktionsumgebung gibt es in einer Transaktion häufig mehr als eine SQL-Anweisung, sondern eine Sammlung mehrerer SQL-Anweisungen. Was wäre, wenn Sie alle SQL-Anweisungen herausfinden möchten, die in einer nicht festgeschriebenen Transaktion ausgeführt wurden? Tatsächlich gibt es in MySQL eine Möglichkeit. Die folgende SQL-Anweisung kann dies herausfinden oder Wählen Sie trx.trx_mysql_thread_id AS processlist_id ,sc.thread_id ,trx.trx_started ,TO_SECONDS(jetzt())-TO_SECONDS(trx_started) AS trx_last_time ,pc1.Benutzer ,pc1.host ,pc1.db ,sc.SQL_TEXT AS aktueller_SQL_text ,sh.history_sql_test VON INFORMATION_SCHEMA.INNODB_TRX trx INNER JOIN INFORMATION_SCHEMA.processlist pc1 ON trx.trx_mysql_thread_id=pc1.id INNER JOIN performance_schema.threads th auf th.processlist_id = trx.trx_mysql_thread_id INNER JOIN performance_schema.events_statements_current sc ON sc.THREAD_ID = th.THREAD_ID Innerer Join ( Wählen Sie Thread-ID als Thread-ID, GROUP_CONCAT (SQL_TEXT SEPARATOR ';') als Verlauf_SQL_Test VON performance_schema.events_statements_history GRUPPE NACH Thread-ID ) sh EIN sh.thread_id = th.thread_id WO trx_mysql_thread_id != Verbindungs-ID() UND TO_SECONDS(jetzt())-TO_SECONDS(trx_started) >= 0; Bei diesen beiden SQL-Anweisungen gibt es jedoch ein Problem: Sie finden alle SQL-Anweisungen, die im Verlauf der aktuellen Verbindung ausgeführt wurden (vorausgesetzt natürlich, dass diese SQL-Anweisungen noch in der Tabelle performance_schema.events_statements_history gespeichert sind). Mit anderen Worten, diese SQL-Anweisung fragt nicht nur alle Skripte ab, die von nicht festgeschriebenen Transaktionen ausgeführt wurden, sondern fragt auch viele historische SQL-Skripte ab, z. B. die SQL-Anweisungen der Transaktionen vor dieser Sitzung (Verbindung). Darüber hinaus gibt es ein noch problematischeres Problem: Es ist schwierig zu unterscheiden, welche SQL-Anweisungen welchen Transaktionen entsprechen. Zur Identifizierung sind weitere Angaben erforderlich. Es ist zeitaufwendig und mühsam. Wie im Screenshot unten gezeigt. Da nur die Systemtabelle information_schema.innodb_trx die Startzeit der Transaktion (trx_started) enthält und andere Systemtabellen keine transaktionsbezogene Zeit haben, können wir nur das Feld TIMER_START in performance_schema.events_statements_history verwenden, um die Zeit abzurufen, zu der die SQL-Ausführung des Ereignisses beginnt, und diese Zeit muss kleiner oder gleich der Startzeit der entsprechenden Transaktion (trx_started) sein. So können wir alle SQL-Anweisungen nicht festgeschriebener Transaktionen aus diesem Durchbruch finden. Im Folgenden finden Sie eine detaillierte Einführung in Felder wie TIMER_START. Die Einführung von TIMER_START, TIMER_END und TIMER_WAIT lautet wie folgt: TIMER_START, TIMER_END, TIMER_WAIT: Zeitinformationen des Ereignisses. Die Werte sind in Pikosekunden (Billionstel Sekunden) angegeben. Die Werte TIMER_START und TIMER_END stellen die Start- und Endzeiten des Ereignisses dar. TIMER_WAIT ist die Zeit (Dauer), die für die Ausführung des Ereignisses benötigt wird Wenn das Ereignis nicht abgeschlossen ist, ist TIMER_END die aktuelle Zeit und TIMER_WAIT die bisher verstrichene Zeit (TIMER_END – TIMER_START). Wenn das TIMED-Feld des entsprechenden Monitors in der Konfigurationstabelle setup_instruments des Überwachungsinstruments auf NO gesetzt ist, werden die Zeitinformationen des Monitors nicht erfasst. Im für dieses Ereignis erfassten Informationsdatensatz sind die Werte der Felder TIMER_START, TIMER_END und TIMER_WAIT alle NULL. Nach langem Testen und Ringen habe ich endlich ein nahezu perfektes SQL gefunden: Wählen Sie @dt_ts: = UNIX_TIMESTAMP (JETZT()); WÄHLEN @dt_timer:=MAX(sh.TIMER_START) VON performance_schema.threads AS t INNER JOIN performance_schema.events_statements_history AS sh EIN t.`THREAD_ID`=sh.`THREAD_ID` WO t.PROCESSLIST_ID=CONNECTION_ID(); SELECT sh.current_schema AS Datenbankname ,t.thread_id ,it.trx_mysql_thread_id AS Verbindungs-ID ,it.trx_id ,sh.Ereignis-ID ,it.trx_state , ERSETZEN(ERSETZEN(ERSETZEN(sh.`SQL_TEXT`,'\n',' '),'\r',' '),'\t',' ') AS ausgeführt_sql ,it.trx_started ,FROM_UNIXTIME(@dt_ts-CAST((@dt_timer-sh.TIMER_START)/1000000000000 AS SIGNED)) AS start_time ,FROM_UNIXTIME(@dt_ts-CAST((@dt_timer-sh.TIMER_END) /1000000000000 AS SIGNED)) AS end_time ,(sh.TIMER_END-sh.TIMER_START)/1000000000000 AS verbrauchte_Sekunden ,sh.TIMER_WAIT/1000000000000 AS warte_Sekunden ,sh.LOCK_TIME/1000000000000 AS Sperrsekunden ,sh.ROWS_AFFECTED AS betroffene_Zeilen ,sh.ROWS_SENT AS send_rows VON performance_schema.threads AS t INNER JOIN information_schema.innodb_trx es ON es.trx_mysql_thread_id = t.processlist_id INNER JOIN performance_schema.events_statements_history AS sh EIN t.`THREAD_ID`=sh.`THREAD_ID` WO t.PROCESSLIST_ID IN ( WÄHLEN p.ID AS conn_id VON `information_schema`.`INNODB_TRX` t INNER JOIN `information_schema`.`PROCESSLIST` p EIN t.trx_mysql_thread_id=p.id WO t.trx_state='LÄUFT' UND p.COMMAND='Schlaf' UND p.ZEIT>2 ) UND sh.TIMER_START<@dt_timer UND FROM_UNIXTIME(@dt_ts-CAST((@dt_timer-sh.TIMER_START)/1000000000000 AS SIGNED)) >=it.trx_started ORDER BY it.trx_id ASC, sh.TIMER_START ASC; Es kann das SQL nicht festgeschriebener Transaktionen ermitteln. Mit einem einfachen Test gibt es kein Problem, und es ist auch in Ordnung, mehrere Tests nicht festgeschriebener Transaktionen gleichzeitig durchzuführen. Allerdings besteht das obige SQL aus drei SQLs, was sich immer etwas seltsam anfühlt. Nach einigen Recherchen habe ich festgestellt, dass es in das folgende SQL umgewandelt werden kann. SELECT sh.current_schema AS Datenbankname ,t.thread_id ,it.trx_mysql_thread_id AS Verbindungs-ID ,it.trx_id ,sh.Ereignis-ID ,it.trx_state , ERSETZEN(ERSETZEN(ERSETZEN(sh.`SQL_TEXT`,'\n',' '),'\r',' '),'\t',' ') AS ausgeführt_sql ,it.trx_started ,DATE_SUB(NOW(), INTERVAL (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='UPTIME') - sh.TIMER_START*10e-13 Sekunde) AS start_time ,DATE_SUB(NOW(), INTERVAL (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='UPTIME') - sh.TIMER_END*10e-13 Sekunde) AS end_time ,(sh.TIMER_END-sh.TIMER_START)/1000000000000 AS verbrauchte_Sekunden ,sh.TIMER_WAIT/1000000000000 AS warte_Sekunden ,sh.LOCK_TIME/1000000000000 AS Sperrsekunden ,sh.ROWS_AFFECTED AS betroffene_Zeilen ,sh.ROWS_SENT AS send_rows VON performance_schema.threads AS t INNER JOIN information_schema.innodb_trx es ON es.trx_mysql_thread_id = t.processlist_id INNER JOIN performance_schema.events_statements_history AS sh EIN t.`THREAD_ID`=sh.`THREAD_ID` WO t.PROCESSLIST_ID IN ( WÄHLEN p.ID AS conn_id VON `information_schema`.`INNODB_TRX` t INNER JOIN `information_schema`.`PROCESSLIST` p EIN t.trx_mysql_thread_id=p.id WO t.trx_state='LÄUFT' UND p.COMMAND='Schlaf' UND p.ZEIT>2 ) UND sh.TIMER_START <(SELECT VARIABLE_VALUE*1000000000000 FROM performance_schema.global_status WHERE VARIABLE_NAME='UPTIME') UND DATE_SUB(NOW(), INTERVAL (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='UPTIME') - sh.TIMER_START*10e-13 Sekunde) >= it.trx_started ORDER BY it.trx_id ASC, sh.TIMER_START ASC; Hinweis: performance_schema.global_status wurde in MySQL 5.7 eingeführt. Wenn die Datenbank MySQL 5.6 ist, können Sie performance_schema.global_status in SQL durch INFORMATION_SCHEMA.GLOBAL_STATUS ersetzen. Ist dieses SQL also unbedingt perfekt? Netizen MSSQL123 hat gemeldet, dass das obige SQL in einer Testumgebung keine Daten finden konnte, da FROM_UNIXTIME(@dt_ts-CAST((@dt_timer-sh.TIMER_START)/1000000000000 AS SIGNED)) >=it.trx_started die Daten herausfiltern würde. Es wurde festgestellt, dass die entsprechenden trx_started-Werte alle größer als start_time waren. -------------------------------------------------------------------------Ergänzende Angaben---------------------------------------------------------------------------------------------------- Dann wurde in derselben Testumgebung beim Testen am nächsten Tag plötzlich festgestellt, dass die erste SQL-Anweisung oben normal war, die zweite SQL-Anweisung jedoch aufgrund unterschiedlicher Schreibmethoden einen geringfügigen Unterschied in der Startzeit aufwies, was zu völlig unterschiedlichen Abfrageergebnissen führte (die zweite SQL-Anweisung war auf Millisekunden genau und aufgrund von Abweichungen beim Vergleich wurde ein Datenstapel herausgefiltert). ------------------------------------------------------------------------------------------------------------------------------------------------ Bei der Suche nach relevanten Dokumenten habe ich erfahren, dass der Feldwert TIMER_START schwanken oder abweichen kann und dass diese Schwankung oder Abweichung die Abfrageergebnisse beeinflussen kann. Der folgende Inhalt stammt von http://porthos.ist.utl.pt/docs/mySQL/performance-schema.html
Eine der Passagen wird wie folgt übersetzt: Bei den Pikosekundenwerten für Ereignisse handelt es sich um Näherungswerte. Ihre Genauigkeit wird durch häufige Fehler bei der Umrechnung von einer Einheit in eine andere beeinträchtigt. Bei Verwendung des CYCLE-Timers und variierender Prozessorgeschwindigkeit kann es zu Abweichungen kommen. Aus diesen Gründen ist es nicht sinnvoll, den TIMER_START-Wert eines Ereignisses als genaues Maß für die Zeit zu betrachten, die seit dem Start des Servers vergangen ist. Andererseits ist es sinnvoll, TIMER_START- oder TIMER_WAIT-Werte in der ORDER BY-Klausel zu verwenden, um Ereignisse nach Startzeit oder Dauer zu sortieren. Wir möchten das Problem oft mit einem Schlag lösen, aber aufgrund der komplexen Umgebung und einiger unkontrollierbarer Faktoren ist die Realität oft genauso grausam wie „es gibt kein Allheilmittel“. Wenn die Schwankung oder Abweichung von TIMER_START die Abfrageergebnisse beeinflusst, müssen wir eine große Anzahl von SQLs über die SQLs im vorherigen Artikel finden und dann manuell über andere Felder oder Informationen identifizieren, bei welchen SQLs es sich um nicht festgeschriebene Transaktionen handelt. Quellen: https://stackoverflow.com/questions/25607249/mysql-performance-schema-how-to-get-event-time-from-events-statements-current-ta http://porthos.ist.utl.pt/docs/mySQL/performance-schema.html https://dev.mysql.com/doc/refman/5.7/en/performance-schema-timing.html https://dev.mysql.com/doc/refman/8.0/en/performance-schema-timing.html Dies ist das Ende dieses Artikels zum Auffinden nicht festgeschriebener SQL-Transaktionen in MySQL. Weitere Informationen zum Auffinden nicht festgeschriebener SQL-Transaktionen in MySQL 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:
|
<<: Detaillierte Erläuterung des Vue-Entwicklungssortierungskomponentencodes
>>: Der Unterschied und die Verwendung zwischen div und span
Als ich das erste Mal anfing, fand ich viele Fehl...
System: Ubuntu 16.04LTS 1\Laden Sie mysql-5.7.18-...
Inhaltsverzeichnis Vorwort: Systemanforderungen: ...
Heute werde ich Ihnen zeigen, wie Sie das Linux-S...
In Fortsetzung des vorherigen Artikels erstellen ...
Heute habe ich auf CSDN einen kleinen Trick zum Es...
Vorwort Dieser Artikel stellt hauptsächlich die r...
Ein MySQL Custom Value ist ein temporärer Contain...
Besonderer Hinweis: Dieser Artikel wurde basieren...
Vorwort Dieser Artikel stellt die fünfte Frage vo...
1. Entpacken Sie das komprimierte MySQL-Paket in ...
1. Seitenanforderungen 1) Verwenden Sie standardm...
Da ich selbst eine Webseite schreiben möchte, lern...
Mehrere häufig verwendete String-Methoden in Java...
Eine Umgebung Installieren Sie VMware Tools auf C...