Vorwort MySQL ist eine relationale Datenbank mit leistungsstarken Abfragefunktionen, hoher Datenkonsistenz, hoher Datensicherheit und Unterstützung für sekundäre Indizes. Allerdings ist die Leistung etwas schlechter als bei nicht-relationalen Datenbanken, und insbesondere bei mehr als einer Million Daten kommt es häufig zu langsamen Abfragen. Zu diesem Zeitpunkt müssen Sie die Gründe für die langsame Abfrage analysieren. Im Allgemeinen liegt dies an der schlechten SQL-Schreibweise des Programmierers, dem Fehlen eines Schlüsselindex oder dem ungültigen Index. Besonders wichtig ist hierbei der von MySQL bereitgestellte EXPLAIN-Befehl, der die SELECT-Anweisung analysieren und detaillierte Informationen zur SELECT-Ausführung ausgeben kann, damit Entwickler diese gezielt optimieren können. Und fügen Sie vor der Abfrageanweisung einfach „Explain“ hinzu: EXPLAIN SELECT * FROM Kunde WHERE id < 100; Vorbereiten Zuerst müssen Sie zwei Testtabellen und Daten erstellen: CREATE TABLE `Kunde` ( `id` BIGINT(20) unsigned NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NICHT NULL STANDARD '', `Alter` INT(11) unsigned DEFAULT NULL, Primärschlüssel (`id`), SCHLÜSSEL `name_index` (`name`) ) ENGINE = InnoDB STANDARD-CHARSET = utf8mb4 INSERT INTO Kunde (Name, Alter) VALUES ('a', 1); INSERT INTO Kunde (Name, Alter) VALUES ('b', 2); INSERT INTO Kunde (Name, Alter) VALUES ('c', 3); INSERT INTO Kunde (Name, Alter) VALUES ('d', 4); INSERT INTO Kunde (Name, Alter) VALUES ('e', 5); INSERT INTO Kunde (Name, Alter) VALUES ('f', 6); INSERT INTO Kunde (Name, Alter) VALUES ('g', 7); INSERT INTO Kunde (Name, Alter) VALUES ('h', 8); INSERT INTO Kunde (Name, Alter) VALUES ('i', 9); CREATE TABLE `Bestellungen` ( `id` BIGINT(20) unsigned NOT NULL AUTO_INCREMENT, `user_id` BIGINT(20) unsigniert NICHT NULL STANDARD 0, `product_name` VARCHAR(50) NICHT NULL STANDARD '', `productor` VARCHAR(30) NICHT NULL STANDARD '', Primärschlüssel (`id`), SCHLÜSSEL `user_product_detail_index` (`Benutzer-ID`, `Produktname`, `Produkthersteller`) ) ENGINE = InnoDB STANDARD-CHARSET = utf8mb4 INSERT INTO Bestellungen (Benutzer-ID, Produktname, Hersteller) VALUES (1, „p1“, „WHH“); INSERT INTO Bestellungen (Benutzer-ID, Produktname, Hersteller) VALUES (1, „p2“, „WL“); INSERT INTO Bestellungen (Benutzer-ID, Produktname, Hersteller) VALUES (1, „p1“, „DX“); INSERT INTO Bestellungen (Benutzer-ID, Produktname, Hersteller) VALUES (2, „p1“, „WHH“); INSERT INTO Bestellungen (Benutzer-ID, Produktname, Hersteller) VALUES (2, „p5“, „WL“); INSERT INTO Bestellungen (Benutzer-ID, Produktname, Hersteller) VALUES (3, „p3“, „MA“); INSERT INTO Bestellungen (Benutzer-ID, Produktname, Hersteller) VALUES (4, „p1“, „WHH“); INSERT INTO Bestellungen (Benutzer-ID, Produktname, Hersteller) VALUES (6, 'p1', 'WHH'); INSERT INTO Bestellungen (Benutzer-ID, Produktname, Hersteller) VALUES (9, 'p8', 'TE'); EXPLAIN-Ausgabeformat Die Ausgabe des EXPLAIN-Befehls lautet ungefähr wie folgt: mysql> erklären select * from customer where id = 1\G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Kunde Partitionen: NULL Typ: const mögliche Schlüssel: PRIMARY Schlüssel: PRIMARY Schlüssellänge: 8 Verweis: const Reihen: 1 gefiltert: 100,00 Extra: NULL 1 Zeile im Satz, 1 Warnung (0,00 Sek.) Die einzelnen Spalten haben folgende Bedeutung:
Schauen wir uns als Nächstes einige der wichtigeren Felder an. Wählen Sie Typ
Der häufigste Abfragetyp sollte SIMPLE sein. Wenn unsere Abfrage beispielsweise keine Unterabfrage oder UNION-Abfrage hat, ist sie normalerweise vom Typ SIMPLE, zum Beispiel: mysql> erklären select * from customer where id = 2\G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Kunde Partitionen: NULL Typ: const mögliche Schlüssel: PRIMARY Schlüssel: PRIMARY Schlüssellänge: 8 Verweis: const Reihen: 1 gefiltert: 100,00 Extra: NULL 1 Zeile im Satz, 1 Warnung (0,00 Sek.) Wenn wir eine UNION-Abfrage verwenden, sieht die EXPLAIN-Ausgabe ungefähr wie folgt aus: mysql> EXPLAIN (SELECT * FROM Kunde WHERE id IN (1, 2, 3)) -> UNION -> (SELECT * FROM Kunde WHERE id IN (3, 4, 5)); +----+--------------+------------+------------+-------+---------------+--------+---------+---------+------+------+------+-----------------+ | ID | Auswahltyp | Tabelle | Partitionen | Typ | mögliche Schlüssel | Schlüssel | Schlüssellänge | Ref. | Zeilen | gefiltert | Extra | +----+--------------+------------+------------+-------+---------------+--------+---------+---------+------+------+------+-----------------+ | 1 | PRIMARY | Kunde | NULL | Bereich | PRIMARY | PRIMARY | 8 | NULL | 3 | 100,00 | Verwenden von „where“ | | 2 | UNION | Kunde | NULL | Bereich | PRIMARY | PRIMARY | 8 | NULL | 3 | 100,00 | Verwenden von „where“ | | NULL | UNION-ERGEBNIS | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Temporäre | verwenden | +----+--------------+------------+------------+-------+---------------+--------+---------+---------+------+------+------+-----------------+ 3 Zeilen im Satz, 1 Warnung (0,00 Sek.) Tisch Gibt die Tabelle oder abgeleitete Tabelle an, die in der Abfrage enthalten ist. Typ Das Typfeld ist wichtig, da es eine wichtige Grundlage für die Beurteilung der Effizienz der Abfrage bietet. Über das Typfeld können wir beurteilen, ob es sich bei der Abfrage um einen vollständigen Tabellenscan oder einen Indexscan handelt. Typ Gängige Typen Übliche Werte für Typ sind:
mysql> erklären select * from customer where id = 2\G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Kunde Partitionen: NULL Typ: const mögliche Schlüssel: PRIMARY Schlüssel: PRIMARY Schlüssellänge: 8 Verweis: const Reihen: 1 gefiltert: 100,00 Extra: NULL 1 Zeile im Satz, 1 Warnung (0,00 Sek.) eq_ref: Dieser Typ erscheint normalerweise in Verknüpfungsabfragen mit mehreren Tabellen und gibt an, dass für jedes Ergebnis der vorherigen Tabelle nur eine Ergebniszeile in der nächsten Tabelle abgeglichen werden kann. Und die Vergleichsoperation der Abfrage ist normalerweise =, was eine hohe Abfrageeffizienz aufweist. Beispiel: mysql> EXPLAIN SELECT * FROM Kunde, Bestellinfo WHERE Kunden-ID = Bestellinfo.Benutzer-ID\G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Bestellinfo Partitionen: NULL Typ: Index mögliche Schlüssel: Benutzer-Produktdetailindex Schlüssel: user_product_detail_index Schlüssellänge: 314 Ref: NULL Reihen: 9 gefiltert: 100,00 Extra: Verwenden von „where“; Verwenden von „index“ *************************** 2. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Kunde Partitionen: NULL Typ: eq_ref mögliche Schlüssel: PRIMARY Schlüssel: PRIMARY Schlüssellänge: 8 Referenz: test.order_info.user_id Reihen: 1 gefiltert: 100,00 Extra: NULL 2 Zeilen im Satz, 1 Warnung (0,00 Sek.) Ref.: Dieser Typ erscheint normalerweise in Verknüpfungsabfragen für mehrere Tabellen, für nicht eindeutige oder nicht auf Primärschlüsseln basierende Indizes oder für Abfragen, die den ganz linken Präfixregelindex verwenden. Im folgenden Beispiel wird beispielsweise die Abfrage vom Typ „Ref“ verwendet: mysql> EXPLAIN SELECT * FROM Kunde, Bestellinfo WHERE Kunden-ID = Bestellinfo.Benutzer-ID AND Bestellinfo.Benutzer-ID = 5\G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Kunde Partitionen: NULL Typ: const mögliche Schlüssel: PRIMARY Schlüssel: PRIMARY Schlüssellänge: 8 Verweis: const Reihen: 1 gefiltert: 100,00 Extra: NULL *************************** 2. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Bestellinfo Partitionen: NULL Typ: ref mögliche Schlüssel: Benutzer-Produktdetailindex Schlüssel: user_product_detail_index Schlüssellänge: 9 Verweis: const Reihen: 1 gefiltert: 100,00 Extra: Index verwenden 2 Zeilen im Satz, 1 Warnung (0,01 Sek.) Bereich: Gibt an, dass eine Indexbereichsabfrage verwendet wird, um über den Indexfeldbereich partielle Datensätze in der Tabelle abzurufen. Dieser Typ erscheint normalerweise in den Operationen =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN(). Wenn der Typ Bereich ist, ist das von EXPLAIN ausgegebene Referenzfeld NULL und das Feld key_len ist der längste Index, der in dieser Abfrage verwendet wird. Das folgende Beispiel ist beispielsweise eine Bereichsabfrage: mysql> EXPLAIN SELECT * FROM customer WHERE id ZWISCHEN 2 UND 8 \G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Kunde Partitionen: NULL Typ: Bereich mögliche Schlüssel: PRIMARY Schlüssel: PRIMARY Schlüssellänge: 8 Ref: NULL Reihen: 7 gefiltert: 100,00 Extra: Verwenden von „where“ 1 Zeile im Satz, 1 Warnung (0,00 Sek.) Index: Gibt einen vollständigen Indexscan an, der dem Typ ALL ähnelt, mit der Ausnahme, dass der Typ ALL die gesamte Tabelle scannt, während der Typ Index nur alle Indizes scannt, ohne Daten zu scannen. Der Indextyp wird normalerweise angezeigt, wenn die abzufragenden Daten direkt im Indexbaum abgerufen werden können, ohne dass die Daten gescannt werden müssen. In diesem Fall wird im Feld „Extra“ „Index wird verwendet“ angezeigt. Zum Beispiel: mysql> EXPLAIN SELECT Name FROM Kunde \G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Kunde Partitionen: NULL Typ: Index mögliche Schlüssel: NULL Schlüssel: name_index Schlüssellänge: 152 Ref: NULL Reihen: 10 gefiltert: 100,00 Extra: Index verwenden 1 Zeile im Satz, 1 Warnung (0,00 Sek.) Im obigen Beispiel ist das von uns abgefragte Namensfeld zufällig ein Index, sodass wir die Daten direkt aus dem Index abrufen können, um die Abfrageanforderungen zu erfüllen, ohne die Daten in der Tabelle abzufragen. Daher ist in diesem Fall der Wert von Typ Index und der Wert von Extra ist Index verwenden.
Nachfolgend sehen Sie ein Beispiel für einen vollständigen Tabellenscan. Sie können sehen, dass im vollständigen Tabellenscan sowohl die Possible_Keys- als auch die Key-Felder NULL sind, was darauf hinweist, dass kein Index verwendet wird. Außerdem sind die Zeilen sehr groß, sodass die Gesamtabfrageeffizienz sehr gering ist. mysql> EXPLAIN SELECT age FROM customer WHERE age = 20 \G**************************** 1. Zeile *************************** ID: 1 select_type: EINFACH Tabelle: Kunde Partitionen: NULL Typ: ALLE mögliche Schlüssel: NULL Schlüssel: NULL key_len: NULL Ref: NULL Reihen: 10 gefiltert: 10.00 Extra: Verwenden von „where“ 1 Zeile im Satz, 1 Warnung (0,00 Sek.) Leistungsvergleich von Typ Im Allgemeinen ist das Leistungsverhältnis zwischen den verschiedenen Typen wie folgt:
Der Typ „ALL“ ist der langsamste, da es sich um einen vollständigen Tabellenscan unter denselben Abfragebedingungen handelt. Obwohl die Abfrage vom Indextyp nicht die gesamte Tabelle durchsucht, durchsucht sie alle Indizes und ist daher etwas schneller als der Typ ALL. Die folgenden Typen verwenden alle Indizes zum Abfragen von Daten, sodass sie einen Teil oder die meisten Daten filtern können, sodass die Abfrageeffizienz relativ hoch ist. Wenn ein Programmierer sicherstellen kann, dass die Abfrage mindestens die Bereichsebene oder besser noch die Referenzebene erreicht, gilt er als hervorragender und verantwortungsvoller Programmierer.
möglicher_Schlüssel Possible_keys gibt die Indizes an, die MySQL bei Abfragen verwenden kann. Beachten Sie, dass selbst wenn einige Indizes in Possible_keys erscheinen, dies nicht bedeutet, dass dieser Index tatsächlich von MySQL verwendet wird. Die spezifischen Indizes, die MySQL bei Abfragen verwendet, werden durch das Schlüsselfeld bestimmt. Schlüssel Dieses Feld ist der Index, den MySQL tatsächlich in der aktuellen Abfrage verwendet. Schlüssellänge Gibt die Anzahl der vom Abfrageoptimierer verwendeten Bytes an. Mit diesem Feld kann ausgewertet werden, ob der zusammengesetzte Index vollständig verwendet wird oder nur die Felder ganz links verwendet werden. Die Berechnungsregeln für key_len lauten wie folgt:
Betrachten wir zwei einfache Beispiele: mysql> EXPLAIN SELECT * FROM order_info WHERE user_id < 3 AND product_name = 'p1' AND productor = 'WHH' \G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Bestellinfo Partitionen: NULL Typ: Bereich mögliche Schlüssel: Benutzer-Produktdetailindex Schlüssel: user_product_detail_index Schlüssellänge: 9 Ref: NULL Reihen: 5 gefiltert: 11.11 Extra: Verwenden von „where“; Verwenden von „index“ 1 Zeile im Satz, 1 Warnung (0,00 Sek.) Das obige Beispiel fragt den angegebenen Inhalt aus der Tabelle order_info ab. Aus der Anweisung zur Tabellenerstellung können wir erkennen, dass die Tabelle order_info einen gemeinsamen Index hat: SCHLÜSSEL `user_product_detail_index` (`Benutzer-ID`, `Produktname`, `Produkthersteller`) In der Abfrage WHERE user_id < 3 AND product_name = 'p1' AND productor = 'WHH' wird jedoch zuerst die user_id-Bereichsabfrage ausgeführt. Gemäß dem Prinzip des ganz linken Präfixabgleichs wird der Indexabgleich beendet, wenn eine Bereichsabfrage gefunden wird. Daher ist user_id tatsächlich das einzige Indexfeld, das wir verwenden. Daher ist in EXPLAIN die angezeigte key_len 9. Da das user_id-Feld BIGINT ist, belegt es 8 Bytes und das NULL-Attribut belegt ein Byte, sodass die Gesamtsumme 9 Bytes beträgt. Wenn wir das user_id-Feld in BIGINT(20) NOT NULL DEFAULT '0' ändern, sollte die key_length 8 sein. Aufgrund des Prinzips des ganz linken Präfixabgleichs verwendet unsere Abfrage nur das Feld user_id des gemeinsamen Index, sodass die Effizienz nicht hoch ist. Schauen wir uns das nächste Beispiel an: mysql> EXPLAIN SELECT * FROM order_info WHERE user_id = 1 AND product_name = 'p1' \G; *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Bestellinfo Partitionen: NULL Typ: ref mögliche Schlüssel: Benutzer-Produktdetailindex Schlüssel: user_product_detail_index Schlüssellänge: 161 Verweis: konstant, konstant Reihen: 2 gefiltert: 100,00 Extra: Index verwenden 1 Zeile im Satz, 1 Warnung (0,00 Sek.) In dieser Abfrage haben wir keine Bereichsabfrage verwendet und der Wert von key_len ist 161. Warum? Weil in unserer Abfragebedingung WHERE user_id = 1 AND product_name = 'p1' nur die ersten beiden Felder im gemeinsamen Index verwendet werden, also keyLen(user_id) + keyLen(product_name) = 9 + 50 * 3 + 2 = 161 Reihen Zeilen sind ebenfalls ein wichtiges Feld. Basierend auf den Statistiken schätzt der MySQL-Abfrageoptimierer die Anzahl der Zeilen, die SQL scannen muss, um den Ergebnissatz zu finden. Dieser Wert zeigt direkt die Effizienz von SQL. Grundsätzlich gilt: je weniger Zeilen, desto besser. Extra Im Feld „Extra“ werden in „EXplain“ zahlreiche Zusatzinformationen angezeigt. Die häufigsten sind die folgenden:
Wenn „Using Filesort“ im Extra-Modus ist, bedeutet dies, dass MySQL zusätzliche Sortiervorgänge benötigt und den Sortiereffekt nicht über die Indexreihenfolge erzielen kann. Generell wird empfohlen, „Using Filesort“ zu optimieren und zu entfernen, da solche Abfragen viele CPU-Ressourcen verbrauchen. Beispielsweise das folgende Beispiel: mysql> EXPLAIN SELECT * FROM order_info WHERE user_id = 1 AND product_name = 'p1' \G; *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Bestellinfo Partitionen: NULL Typ: ref mögliche Schlüssel: Benutzer-Produktdetailindex Schlüssel: user_product_detail_index Schlüssellänge: 161 Verweis: konstant, konstant Reihen: 2 gefiltert: 100,00 Extra: Index verwenden 1 Zeile im Satz, 1 Warnung (0,00 Sek.) Unser Index ist SCHLÜSSEL `user_product_detail_index` (`Benutzer-ID`, `Produktname`, `Produkthersteller`) Die obige Abfrage ist jedoch nach Produktname sortiert, sodass der Index nicht zur Optimierung verwendet werden kann, was zur Verwendung von Filesort führt. Wenn wir die Sortierbasis in ORDER BY user_id, product_name ändern, wird Using filesort nicht angezeigt. Beispiel: mysql> EXPLAIN SELECT * FROM Bestellinfo ORDER BY Benutzer-ID, Produktname \G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: Bestellinfo Partitionen: NULL Typ: Index mögliche Schlüssel: NULL Schlüssel: user_product_detail_index Schlüssellänge: 253 Ref: NULL Reihen: 9 gefiltert: 100,00 Extra: Index verwenden 1 Zeile im Satz, 1 Warnung (0,00 Sek.)
"Abdeckender Index-Scan" bedeutet, dass die Abfrage die erforderlichen Daten im Indexbaum finden kann, ohne die Tabellendatendatei zu scannen, was häufig auf eine gute Leistung hinweist
Die Abfrage verwendet temporäre Tabellen, die normalerweise in Sortier-, Gruppierungs- und Mehrtabellenverknüpfungssituationen vorkommen. Die Abfrageeffizienz ist nicht hoch. Es wird empfohlen, sie zu optimieren. 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:
|
<<: Analyse der zum Ausführen von Docker erforderlichen Berechtigungen
>>: So installieren Sie Composer unter Linux
Schauen wir uns zunächst den Code an <form id=...
Aufgrund der Geschäftsanforderungen des Unternehm...
Inhaltsverzeichnis 1. Einleitung 2. Erstellen Sie...
DOCTYPE-DEKLARATION: Oben auf jeder Seite, die Sie...
Inhaltsverzeichnis 1. Laden Sie nodejs herunter 2...
In diesem Artikel wird die Verwendung von „Explai...
Inhaltsverzeichnis 1. Übersicht 2. nginx.conf 1) ...
Über Nginx, eine leistungsstarke, leichte Webserv...
Inhaltsverzeichnis 01 Einführung in Atomic DDL 02...
mysql5.5.28 Installations-Tutorial zu Ihrer Infor...
Dieser Artikel beschreibt anhand von Beispielen, ...
Überblick Dieser Artikel stellt die in Spieleclie...
Dieser Artikel stellt hauptsächlich den relevante...
Projektszenario: Dark Horse Vue Projektmanagement...
In diesem Artikel finden Sie das Installations- u...