Das MySQL-Entwicklungsteam hat am 14. Oktober 2019 die MySQL 8.0.18 GA-Version offiziell veröffentlicht, die einige neue Funktionen und Verbesserungen mit sich bringt. Das auffälligste Merkmal ist, dass Multi-Table-Join-Abfragen den Hash-Join-Modus unterstützen. Werfen wir zunächst einen Blick auf die offizielle Beschreibung: MySQL implementiert eine Hash-Join-Methode für Inner-Join-Abfragen. Ab MySQL 8.0.18 kann beispielsweise die folgende Abfrage Hash-Join für Join-Abfragen verwenden: WÄHLEN * VON t1 t2 beitreten EIN t1.c1=t2.c1; Hash-Join erfordert keine Indexunterstützung. In den meisten Fällen ist der Hash-Join effizienter als der vorherige Block-Nested-Loop-Algorithmus für gleichwertige Joins ohne Indizes. Verwenden Sie die folgenden Anweisungen, um drei Testtabellen zu erstellen: TABELLE ERSTELLEN t1 (c1 INT, c2 INT); TABELLE ERSTELLEN t2 (c1 INT, c2 INT); TABELLE ERSTELLEN t3 (c1 INT, c2 INT); Verwenden Sie den Befehl EXPLAIN FORMAT=TREE, um den Hash-Join im Ausführungsplan anzuzeigen, zum Beispiel: mysql> EXPLAIN FORMAT=BAUM -> AUSWÄHLEN * -> VON t1 -> t2 beitreten -> EIN t1.c1=t2.c1\G *************************** 1. Reihe *************************** ERKLÄRUNG: -> Innerer Hash-Join (t2.c1 = t1.c1) (Kosten=0,70 Zeilen=1) -> Tabellenscan auf t2 (Kosten=0,35 Zeilen=1) -> Hash -> Tabellenscan auf t1 (Kosten=0,35 Zeilen=1) Sie müssen die Option FORMAT=TREE des Befehls EXPLAIN verwenden, um die Hash-Joins im Knoten anzuzeigen. Darüber hinaus kann der Befehl EXPLAIN ANALYZE auch die Verwendungsinformationen des Hash-Joins anzeigen. Dies ist auch eine neue Funktion, die dieser Version hinzugefügt wurde. Auch Abfragen, die Equi-Joins zwischen mehreren Tabellen verwenden, werden auf diese Weise optimiert. Beispielsweise die folgende Abfrage: WÄHLEN * VON t1 t2 beitreten EIN (t1.c1 = t2.c1 UND t1.c2 < t2.c2) WERDEN SIE MITGLIED bei t3 EIN (t2.c1 = t3.c1); Im obigen Beispiel werden alle anderen Nicht-Equijoin-Bedingungen nach der Join-Operation als Filter verwendet. Sie können dies in der Ausgabe des Befehls EXPLAIN FORMAT=TREE sehen: mysql> EXPLAIN FORMAT=BAUM -> AUSWÄHLEN * -> VON t1 -> t2 beitreten -> EIN (t1.c1 = t2.c1 UND t1.c2 < t2.c2) -> t3 beitreten -> EIN (t2.c1 = t3.c1)\G *************************** 1. Reihe *************************** ERKLÄRUNG: -> Innerer Hash-Join (t3.c1 = t1.c1) (Kosten=1,05 Zeilen=1) -> Tabellenscan auf t3 (Kosten=0,35 Zeilen=1) -> Hash -> Filter: (t1.c2 < t2.c2) (Kosten=0,70 Zeilen=1) -> Innerer Hash-Join (t2.c1 = t1.c1) (Kosten=0,70 Zeilen=1) -> Tabellenscan auf t2 (Kosten=0,35 Zeilen=1) -> Hash -> Tabellenscan auf t1 (Kosten=0,35 Zeilen=1) Aus der obigen Ausgabe ist außerdem ersichtlich, dass Abfragen, die mehrere gleiche Join-Bedingungen enthalten, auch mehrere Hash-Join-Verbindungen verwenden können (werden). Wenn jedoch eine beliebige Verbindungsanweisung (ON) nicht die entsprechende Verbindungsbedingung verwendet, wird die Hash-Join-Verbindungsmethode nicht verwendet. Zum Beispiel: mysql> EXPLAIN FORMAT=BAUM -> AUSWÄHLEN * -> VON t1 -> t2 beitreten -> EIN (t1.c1 = t2.c1) -> t3 beitreten -> EIN (t2.c1 < t3.c1)\G *************************** 1. Reihe *************************** EXPLAIN: <nicht ausführbar durch Iterator-Executor> Zu diesem Zeitpunkt wird der langsamere mysql> ERKLÄREN -> AUSWÄHLEN * -> VON t1 -> t2 beitreten -> EIN (t1.c1 = t2.c1) -> t3 beitreten -> EIN (t2.c1 < t3.c1)\G *************************** 1. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: t1 Partitionen: NULL Typ: ALLE mögliche Schlüssel: NULL Schlüssel: NULL key_len: NULL Ref: NULL Reihen: 1 gefiltert: 100,00 Extra: NULL *************************** 2. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: t2 Partitionen: NULL Typ: ALLE mögliche Schlüssel: NULL Schlüssel: NULL key_len: NULL Ref: NULL Reihen: 1 gefiltert: 100,00 Extra: Verwenden von „where“; Verwenden des Join-Puffers (Block Nested Loop) *************************** 3. Reihe *************************** ID: 1 select_type: EINFACH Tabelle: t3 Partitionen: NULL Typ: ALLE mögliche Schlüssel: NULL Schlüssel: NULL key_len: NULL Ref: NULL Reihen: 1 gefiltert: 100,00 Extra: Verwenden von „where“; Verwenden des Join-Puffers (Block Nested Loop) Der Hash-Join gilt auch für das kartesische Produkt, wenn keine Abfragebedingungen angegeben sind, zum Beispiel: mysql> EXPLAIN FORMAT=BAUM -> AUSWÄHLEN * -> VON t1 -> t2 beitreten -> WO t1.c2 > 50\G *************************** 1. Reihe *************************** ERKLÄRUNG: -> Innerer Hash-Join (Kosten=0,70 Zeilen=1) -> Tabellenscan auf t2 (Kosten=0,35 Zeilen=1) -> Hash -> Filter: (t1.c2 > 50) (Kosten=0,35 Zeilen=1) -> Tabellenscan auf t1 (Kosten=0,35 Zeilen=1) Standardmäßig verwendet MySQL, sofern möglich, Hash-Joins. Gleichzeitig werden zwei Methoden bereitgestellt, um zu steuern, ob ein Hash-Join verwendet werden soll: Setzen Sie die Serversystemvariable Geben Sie den Optimierungshinweis HASH_JOIN oder NO_HASH_JOIN für einen bestimmten Join auf Anweisungsebene an. Die für den Hash-Join zulässige Speichermenge kann durch die Systemvariable Erhöhen Sie den Wert von Erhöhen Sie den Wert von Als nächstes vergleichen sie die Leistung von setze join_buffer_size=2097152000; SETZEN @@cte_max_recursion_depth = 99999999; EINFÜGEN IN t1 -- IN t2 EINFÜGEN -- IN t3 EINFÜGEN MIT REKURSIVEM t ALS ( WÄHLEN Sie 1 als c1, 1 als c2 UNION ALLE WÄHLEN Sie t.c1 + 1, t.c1 * 2 VON t Wobei t.c1 < 1000000 ) WÄHLEN * VON t; Hash-Join ohne Index: mysql> ERKLÄREN ANALYSIEREN -> ANZAHL AUSWÄHLEN(*) -> VON t1 -> t2 beitreten -> EIN (t1.c1 = t2.c1) -> t3 beitreten -> EIN (t2.c1 = t3.c1)\G *************************** 1. Reihe *************************** ERKLÄRUNG: -> Aggregat: Anzahl(0) (tatsächliche Zeit=22993.098..22993.099 Zeilen=1 Schleifen=1) -> Innerer Hash-Join (t3.c1 = t1.c1) (Kosten=9952535443663536,00 Zeilen=9952435908880402) (tatsächliche Zeit=14489,176..21737,032 Zeilen=1000000 Schleifen=1) -> Tabellenscan in t3 (Kosten=0,00, Zeilen=998412) (tatsächliche Zeit=0,103..3973,892, Zeilen=1000000, Schleifen=1) -> Hash -> Innerer Hash-Join (t2.c1 = t1.c1) (Kosten=99682753413,67 Zeilen=99682653660) (tatsächliche Zeit=5663,592..12236,984 Zeilen=1000000 Schleifen=1) -> Tabellenscan in t2 (Kosten=0,01 Zeilen=998412) (tatsächliche Zeit=0,067..3364,105 Zeilen=1000000 Schleifen=1) -> Hash -> Tabellenscan in t1 (Kosten=100539,40 Zeilen=998412) (tatsächliche Zeit=0,133..3395,799 Zeilen=1000000 Schleifen=1) 1 Reihe im Satz (23,22 Sek.) mysql> ANZAHL AUSWÄHLEN(*) -> VON t1 -> t2 beitreten -> EIN (t1.c1 = t2.c1) -> t3 beitreten -> EIN (t2.c1 = t3.c1); +----------+ | ANZAHL(*) | +----------+ | 1000000 | +----------+ 1 Zeile im Satz (12,98 Sek.) Der eigentliche Lauf dauerte 12,98 Sekunden. Wenn Sie zu diesem Zeitpunkt eine blockverschachtelte Schleife verwenden: mysql> EXPLAIN FORMAT=BAUM -> AUSWÄHLEN /*+ NO_HASH_JOIN(t1, t2, t3) */ ANZAHL(*) -> VON t1 -> t2 beitreten -> EIN (t1.c1 = t2.c1) -> t3 beitreten -> EIN (t2.c1 = t3.c1)\G *************************** 1. Reihe *************************** EXPLAIN: <nicht ausführbar durch Iterator-Executor> 1 Zeile im Satz (0,00 Sek.) AUSWÄHLEN /*+ NO_HASH_JOIN(t1, t2, t3) */ ANZAHL(*) VON t1 t2 beitreten EIN (t1.c1 = t2.c1) WERDEN SIE MITGLIED bei t3 EIN (t2.c1 = t3.c1); EXPLAIN zeigt, dass Hash-Join nicht verwendet werden kann. Die Abfrage lief Dutzende Minuten lang, ohne Ergebnisse zu liefern, und eine der CPUs war zu 100 % ausgelastet, da sie ständig verschachtelte Schleifen ausführte (1.000.000 hoch 3). Schauen wir uns den Block Nested Loop-Methode mit einem Index an und fügen einen Index hinzu: mysql> ERSTELLEN Sie den Index idx1 auf t1 (c1); Abfrage OK, 0 Zeilen betroffen (7,39 Sek.) Datensätze: 0 Duplikate: 0 Warnungen: 0 mysql> ERSTELLEN Sie den Index idx2 auf t2 (c1); Abfrage OK, 0 Zeilen betroffen (6,77 Sek.) Datensätze: 0 Duplikate: 0 Warnungen: 0 mysql> ERSTELLEN Sie den Index idx3 auf t3 (c1); Abfrage OK, 0 Zeilen betroffen (7,23 Sek.) Datensätze: 0 Duplikate: 0 Warnungen: 0 Zeigen Sie den Ausführungsplan an und führen Sie dieselbe Abfrage aus: mysql> ERKLÄREN ANALYSIEREN -> ANZAHL AUSWÄHLEN(*) -> VON t1 -> t2 beitreten -> EIN (t1.c1 = t2.c1) -> t3 beitreten -> EIN (t2.c1 = t3.c1)\G *************************** 1. Reihe *************************** ERKLÄRUNG: -> Aggregat: Anzahl(0) (tatsächliche Zeit=47684.034..47684.035 Zeilen=1 Schleifen=1) -> Innerer Join mit verschachtelter Schleife (Kosten=2295573,22 Zeilen=998412) (tatsächliche Zeit=0,116..46363,599 Zeilen=1000000 Schleifen=1) -> Innerer Join mit verschachtelter Schleife (Kosten=1198056,31 Zeilen=998412) (tatsächliche Zeit=0,087..25788,696 Zeilen=1000000 Schleifen=1) -> Filter: (t1.c1 ist nicht null) (Kosten=100539,40 Zeilen=998412) (tatsächliche Zeit=0,050..5557,847 Zeilen=1000000 Schleifen=1) -> Index-Scan auf t1 mit idx1 (Kosten=100539,40 Zeilen=998412) (tatsächliche Zeit=0,043..3253,769 Zeilen=1000000 Schleifen=1) -> Indexsuche auf t2 mit idx2 (c1=t1.c1) (Kosten=1,00, Zeilen=1) (tatsächliche Zeit=0,012..0,015, Zeilen=1, Schleifen=1000000) -> Indexsuche auf t3 mit idx3 (c1=t1.c1) (Kosten=1,00, Zeilen=1) (tatsächliche Zeit=0,012..0,015, Zeilen=1, Schleifen=1000000) 1 Reihe im Satz (47,68 Sek.) mysql> ANZAHL AUSWÄHLEN(*) -> VON t1 -> t2 beitreten -> EIN (t1.c1 = t2.c1) -> t3 beitreten -> EIN (t2.c1 = t3.c1); +----------+ | ANZAHL(*) | +----------+ | 1000000 | +----------+ 1 Reihe im Satz (19,56 Sek.) Der eigentliche Lauf dauerte 19,56 Sekunden. Die Testergebnisse in unserem Szenario lauten also wie folgt:
Fügen Sie in Oracle 12c ein weiteres Hash-Join-Ergebnis ohne Index hinzu: 1,282 s. Hier ist ein weiteres Hash-Join-Ergebnis ohne Index in PostgreSQL 11.5: 6,234 s. Fügen Sie in SQL 2017 ein weiteres Hash-Join-Ergebnis ohne Index hinzu: 5,207 s. Zusammenfassen Oben ist die neue Funktion von MySQL 8.0, Hash Join, die ich Ihnen vorstellen möchte. Ich hoffe, sie wird Ihnen hilfreich sein. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und ich werde Ihnen rechtzeitig antworten. Ich möchte auch allen für ihre Unterstützung der Website 123WORDPRESS.COM danken! Wenn Sie diesen Artikel hilfreich finden, können Sie ihn gerne abdrucken und dabei bitte die Quelle angeben. Vielen Dank! Das könnte Sie auch interessieren:
|
<<: Verzeichnisberechtigungen beim Erstellen eines Containers mit Docker
>>: Bootstrap+Jquery zum Erreichen eines Kalendereffekts
Bild herunterladen Docker-Pull OpenJDK Erstellen ...
Methode 1: Befehlszeilenänderung Wir müssen nur d...
So installieren Sie Tomcat-8.5.39 auf CentOS 7.6....
Code kopieren Der Code lautet wie folgt: <form...
Vorwort Dieser Artikel fasst hauptsächlich einige...
Code kopieren Der Code lautet wie folgt: <!--[...
Inhaltsverzeichnis Überblick Code-Implementierung...
Ausrichtungsprobleme wie type="radio" un...
Wie lade ich MySQL von der offiziellen Website he...
Nginx kann nicht nur Versionsinformationen verber...
Was sind Routing und Routing-Tabellen in Linux? U...
Inhaltsverzeichnis Vorwort Globale Sperre Tabelle...
Inhaltsverzeichnis 1. Veranstaltungsdelegation Er...
Vorwort Die Rolle des Prozessmanagements: Integri...
Beim Erstellen einer Website habe ich festgestellt...