7 Stimmen

Wie implementiert MySQL die "Gruppierung nach"?

Ich habe im MySQL-Referenzhandbuch nachgelesen und festgestellt, dass es, wenn es den Index nutzen kann, nur einen Index-Scan durchführt, während es in anderen Fällen tmp-Tabellen erstellt und Dinge wie Dateisortierung durchführt. Und ich habe auch in einem anderen Artikel gelesen, dass das "Group By"-Ergebnis standardmäßig nach "Group By"-Spalten sortiert wird, wenn die "order by null"-Klausel hinzugefügt wird, wird es keine Dateisortierung durchführen. Der Unterschied kann von der "explain ..." Klausel gefunden werden. Mein Problem ist also: Was ist die Unterschied zwischen einer "group by"-Klausel mit "order by null" und einer ohne diese Klausel? Ich versuche, Profiling zu verwenden, um zu sehen, was mysql im Hintergrund tun, und sehen nur Ergebnis wie:

result for group clause without order by null:
|preparing                      | 0.000016 | 
| Creating tmp table             | 0.000048 | 
| executing                      | 0.000009 | 
| Copying to tmp table           | 0.000109 | 
**| Sorting result                 | 0.000023 |** 
| Sending data                   | 0.000027 | 

result for clause with "order by null":
preparing                      | 0.000016 | 
| Creating tmp table             | 0.000052 | 
| executing                      | 0.000009 | 
| Copying to tmp table           | 0.000114 | 
| Sending data                   | 0.000028 | 

Also ich vermute, was MySQL tun, wenn die "Reihenfolge nach null" hinzugefügt, es verwendet nicht filesort Algorithmus, vielleicht, wenn es die tmp-Tabelle erstellt, es verwendet Index als auch, und dann verwenden Sie den Index, um Gruppe durch Betrieb zu tun, wenn abgeschlossen, es nur Ergebnis aus den Tabellenzeilen lesen und sortiert das Ergebnis nicht.

Aber meine ursprüngliche Meinung ist, dass MySQL Quicksort verwenden kann, um die Elemente zu sortieren und dann gruppieren nach tun, so dass das Ergebnis auch sortiert werden wird.

Jede Meinung ist willkommen, danke.

1voto

oyishi Punkte 34
mysql> select max(post_date),post_author from wp_posts
-> where id > 10 and id < 1000
-> group by post_author;
+———————+————-+
| max(post_date) | post_author |
+———————+————-+
| 2009-07-03 12:58:39 | 1 |
+———————+————-+
1 row in set (0.01 sec)

mysql> show profiles;
+———-+————+————————+
| Query_ID | Duration | Query |
+———-+————+————————+
| 1 | 0.00013200 | SELECT DATABASE() |
| 2 | 0.00030900 | show databases |
| 3 | 0.00030400 | show tables |
| 4 | 0.01180000 | select max(post_date),post_author from wp_posts where id > 10 and id < 1000 group by post_author |4 rows in set (0.00 sec)

mysql> show profile cpu,block io for query 4;
+———————-+———-+———-+————+————–+—————+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+———————-+———-+———-+————+————–+—————+
| starting | 0.000085 | 0.000000 | 0.000000 | 0 | 0 |
| Opening tables | 0.000010 | 0.000000 | 0.000000 | 0 | 0 |
| System lock | 0.000005 | 0.000000 | 0.000000 | 0 | 0 |
| Table lock | 0.000008 | 0.000000 | 0.000000 | 0 | 0 |
| init | 0.000029 | 0.000000 | 0.000000 | 0 | 0 |
| optimizing | 0.000014 | 0.000000 | 0.000000 | 0 | 0 |
| statistics | 0.000062 | 0.000000 | 0.000000 | 0 | 0 |
| preparing | 0.000016 | 0.000000 | 0.000000 | 0 | 0 |
| Creating tmp table | 0.000035 | 0.000000 | 0.000000 | 0 | 0 |
| executing | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| Copying to tmp table | 0.011386 | 0.004999 | 0.006999 | 0 | 0 |
| Sorting result | 0.000044 | 0.000000 | 0.000000 | 0 | 0 |
| Sending data | 0.000036 | 0.000000 | 0.000000 | 0 | 0 |
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| removing tmp table | 0.000012 | 0.000000 | 0.000000 | 0 | 0 |
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| query end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| freeing items | 0.000013 | 0.000000 | 0.000000 | 0 | 0 |
| closing tables | 0.000018 | 0.000000 | 0.000000 | 0 | 0 |
| logging slow query | 0.000003 | 0.000000 | 0.000000 | 0 | 0 |
| cleaning up | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
+———————-+———-+———-+————+————–+—————+
22 rows in set (0.00 sec)

mysql>
mysql>
mysql> select max(post_date),post_author from wp_posts
-> where id > 10 and id < 1000
-> group by post_author order by null;
+———————+————-+
| max(post_date) | post_author |
+———————+————-+
| 2009-07-03 12:58:39 | 1 |
+———————+————-+
1 row in set (0.01 sec)

mysql> show profiles;
+———-+————+—————–+
| Query_ID | Duration | Query
+———-+————+—————–+
|1 | 0.00013200 | SELECT DATABASE()
|2 | 0.00030900 | show databases
|3 | 0.00030400 | show tables
|4 | 0.01180000 | select max(post_date),post_author from wp_posts where id > 10 and id < 1000 group by post_author
|5 | 0.01177700 | select max(post_date),post_author from wp_posts where id > 10 and id < 1000 group by post_author order by null
5 rows in set (0.00 sec)
mysql> show profile cpu,block io for query 5;
+———————-+———-+———-+————+————–+—————+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+———————-+———-+———-+————+————–+—————+
| starting | 0.000097 | 0.000000 | 0.000000 | 0 | 0 |
| Opening tables | 0.000013 | 0.000000 | 0.000000 | 0 | 0 |
| System lock | 0.000006 | 0.000000 | 0.000000 | 0 | 0 |
| Table lock | 0.000008 | 0.000000 | 0.000000 | 0 | 0 |
| init | 0.000032 | 0.000000 | 0.000000 | 0 | 0 |
| optimizing | 0.000012 | 0.000000 | 0.000000 | 0 | 0 |
| statistics | 0.000065 | 0.000000 | 0.000000 | 0 | 0 |
| preparing | 0.000017 | 0.000000 | 0.000000 | 0 | 0 |
| Creating tmp table | 0.000040 | 0.000000 | 0.000000 | 0 | 0 |
| executing | 0.000003 | 0.000000 | 0.000000 | 0 | 0 |
| Copying to tmp table | 0.011369 | 0.005999 | 0.004999 | 0 | 0 |
| Sending data | 0.000040 | 0.000000 | 0.000000 | 0 | 0 |
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| removing tmp table | 0.000031 | 0.000000 | 0.000000 | 0 | 0 |
| end | 0.000005 | 0.000000 | 0.000000 | 0 | 0 |
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| query end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| freeing items | 0.000012 | 0.000000 | 0.000000 | 0 | 0 |
| closing tables | 0.000009 | 0.000000 | 0.000000 | 0 | 0 |
| logging slow query | 0.000003 | 0.000000 | 0.000000 | 0 | 0 |
| cleaning up | 0.000003 | 0.000000 | 0.000000 | 0 | 0 |
+———————-+———-+———-+————+————–+—————+
21 rows in set (0.00 sec)

Hier können wir sehen, dass der zweite Teil nicht den Schritt "Sortierergebnis" hat, also eine kleine Auswirkung auf die Leistung.

1voto

Die GROUP BY-Klausel erlaubt einen WITH ROLLUP-Modifikator, der bewirkt, dass zusätzliche Zeilen zur Ausgabe der Zusammenfassung hinzugefügt werden. Diese Zeilen stellen übergeordnete (oder super-aggregierte) Zusammenfassungsoperationen dar. Mit ROLLUP können Sie also mit einer einzigen Abfrage Fragen auf mehreren Analyseebenen beantworten. Es kann z. B. zur Unterstützung von OLAP-Operationen (Online Analytical Processing) verwendet werden.

Angenommen, eine Tabelle mit dem Namen "Umsatz" hat Spalten für Jahr, Land, Produkt und Gewinn, um die Umsatzrentabilität zu erfassen:

CREATE TABLE Verkäufe ( jahr INT NOT NULL, land VARCHAR(20) NOT NULL, produkt VARCHAR(32) NOT NULL, gewinn INT );

Der Inhalt der Tabelle kann pro Jahr mit einem einfachen GROUP BY wie folgt zusammengefasst werden:

mysql> SELECT Jahr, SUM(Gewinn) FROM Umsatz GROUP BY Jahr; +------+-------------+ | Jahr | SUM(Gewinn) | +------+-------------+ | 2000 | 4525 | | 2001 | 3010 | +------+-------------+

Diese Ausgabe zeigt den Gesamtgewinn für jedes Jahr, aber wenn Sie auch den Gesamtgewinn über alle Jahre summiert ermitteln wollen, müssen Sie die einzelnen Werte selbst addieren oder eine zusätzliche Abfrage durchführen.

Oder Sie können ROLLUP verwenden, das beide Analyseebenen mit einer einzigen Abfrage ermöglicht. Wenn Sie der GROUP BY-Klausel einen WITH ROLLUP-Modifikator hinzufügen, erzeugt die Abfrage eine weitere Zeile, die die Gesamtsumme aller Jahreswerte anzeigt:

mysql> SELECT Jahr, SUM(Gewinn) FROM Umsatz GROUP BY Jahr WITH ROLLUP; +------+-------------+ | Jahr | SUM(Gewinn) | +------+-------------+ | 2000 | 4525 | | 2001 | 3010 | | NULL | 7535 | +------+-------------+

Die Zeile für das Superaggregat der Gesamtsumme ist durch den Wert NULL in der Spalte Jahr gekennzeichnet.

ROLLUP hat eine komplexere Wirkung, wenn es mehrere GROUP BY-Spalten gibt. In diesem Fall erzeugt die Abfrage jedes Mal, wenn es einen "Bruch" (Wertänderung) in einer der letzten Gruppierungsspalten gibt, eine zusätzliche Super-Aggregat-Zusammenfassungszeile.

Ohne ROLLUP könnte eine Zusammenfassung der Verkaufstabelle nach Jahr, Land und Produkt zum Beispiel so aussehen:

mysql> SELECT Jahr, Land, Produkt, SUM(Gewinn) -> FROM umsatz -> GROUP BY Jahr, Land, Produkt; +------+---------+------------+-------------+ | Jahr | Land | Produkt | SUM(Gewinn) | +------+---------+------------+-------------+ | 2000 | Finnland | Computer | 1500 | | 2000 | Finnland | Telefon | 100 | | 2000 | Indien | Rechner | 150 | | 2000 | Indien | Computer | 1200 | | 2000 | USA | Rechner | 75 | | 2000 | USA | Computer | 1500 | | 2001 | Finnland | Telefon | 10 | | 2001 | USA | Rechner | 50 | | 2001 | USA | Computer | 2700 | | 2001 | USA | TV | 250 | +------+---------+------------+-------------+

Die Ausgabe enthält zusammenfassende Werte nur auf der Analyseebene Jahr/Land/Produkt. Wenn ROLLUP hinzugefügt wird, erzeugt die Abfrage mehrere zusätzliche Zeilen:

mysql> SELECT Jahr, Land, Produkt, SUM(Gewinn) -> FROM umsatz -> GROUP BY Jahr, Land, Produkt WITH ROLLUP; +------+---------+------------+-------------+ | Jahr | Land | Produkt | SUM(Gewinn) | +------+---------+------------+-------------+ | 2000 | Finnland | Computer | 1500 | | 2000 | Finnland | Telefon | 100 | | 2000 | Finnland | NULL | 1600 | | 2000 | Indien | Rechner | 150 | | 2000 | Indien | Computer | 1200 | | 2000 | Indien | NULL | 1350 | | 2000 | USA | Rechner | 75 | | 2000 | USA | Computer | 1500 | | 2000 | USA | NULL | 1575 | | 2000 | NULL | NULL | 4525 | | 2001 | Finnland | Telefon | 10 | | 2001 | Finnland | NULL | 10 | | 2001 | USA | Rechner | 50 | | 2001 | USA | Computer | 2700 | | 2001 | USA | TV | 250 | | 2001 | USA | NULL | 3000 | | 2001 | NULL | NULL | 3010 | | NULL | NULL | NULL | 7535 | +------+---------+------------+-------------+

Bei dieser Abfrage führt das Hinzufügen von ROLLUP dazu, dass die Ausgabe Zusammenfassungsinformationen auf vier Analyseebenen enthält, nicht nur auf einer. Die ROLLUP-Ausgabe ist wie folgt zu interpretieren:

*

  Following each set of product rows for a given year and country, an extra summary row is produced showing the total for all products. These rows have the product column set to NULL.
*

  Following each set of rows for a given year, an extra summary row is produced showing the total for all countries and products. These rows have the country and products columns set to NULL.
*

  Finally, following all other rows, an extra summary row is produced showing the grand total for all years, countries, and products. This row has the year, country, and products columns set to NULL.

Weitere Überlegungen bei der Verwendung von ROLLUP

Die folgenden Punkte führen einige Verhaltensweisen auf, die für die MySQL-Implementierung von ROLLUP spezifisch sind:

Wenn Sie ROLLUP verwenden, können Sie nicht gleichzeitig eine ORDER BY-Klausel verwenden, um die Ergebnisse zu sortieren. Mit anderen Worten: ROLLUP und ORDER BY schließen sich gegenseitig aus. Sie haben jedoch immer noch eine gewisse Kontrolle über die Sortierreihenfolge. GROUP BY in MySQL sortiert die Ergebnisse, und Sie können explizite ASC- und DESC-Schlüsselwörter mit in der GROUP BY-Liste genannten Spalten verwenden, um die Sortierreihenfolge für einzelne Spalten festzulegen. (Die übergeordneten Zusammenfassungszeilen, die durch ROLLUP hinzugefügt werden, erscheinen unabhängig von der Sortierreihenfolge immer noch nach den Zeilen, aus denen sie berechnet werden).

LIMIT kann verwendet werden, um die Anzahl der an den Client zurückgegebenen Zeilen zu begrenzen. LIMIT wird nach ROLLUP angewendet, so dass die Begrenzung für die zusätzlichen Zeilen gilt, die durch ROLLUP hinzugefügt werden. Zum Beispiel:

mysql> SELECT Jahr, Land, Produkt, SUM(Gewinn) -> FROM Verkäufe -> GROUP BY Jahr, Land, Produkt WITH ROLLUP -> LIMIT 5; +------+---------+------------+-------------+ | Jahr | Land | Produkt | SUM(Gewinn) | +------+---------+------------+-------------+ | 2000 | Finnland | Computer | 1500 | | 2000 | Finnland | Telefon | 100 | | 2000 | Finnland | NULL | 1600 | | 2000 | Indien | Rechner | 150 | | 2000 | Indien | Computer | 1200 | +------+---------+------------+-------------+

Die Verwendung von LIMIT mit ROLLUP kann zu Ergebnissen führen, die schwieriger zu interpretieren sind, weil Sie weniger Kontext zum Verständnis der Superaggregatzeilen haben.

Die NULL-Indikatoren in jeder Superaggregatzeile werden erzeugt, wenn die Zeile an den Client gesendet wird. Der Server prüft die in der GROUP BY-Klausel genannten Spalten, die auf die Spalte ganz links folgen, deren Wert sich geändert hat. Für jede Spalte in der Ergebnismenge mit einem Namen, der lexikalisch mit einem dieser Namen übereinstimmt, wird ihr Wert auf NULL gesetzt. (Wenn Sie die Gruppierung der Spalten nach Spaltennummer angeben, identifiziert der Server die auf NULL zu setzenden Spalten anhand der Nummer).

Da die NULL-Werte in den Superaggregat-Zeilen zu einem so späten Zeitpunkt der Abfrageverarbeitung in die Ergebnismenge eingefügt werden, können Sie sie nicht als NULL-Werte innerhalb der Abfrage selbst testen. Sie können zum Beispiel nicht HAVING product IS NULL zur Abfrage hinzufügen, um alle Zeilen außer den Superaggregat-Zeilen aus der Ausgabe zu entfernen.

Andererseits erscheinen die NULL-Werte auf der Client-Seite als NULL und können als solche mit jeder MySQL-Client-Programmierschnittstelle getestet werden.

-1voto

werd Punkte 638

Gruppieren nach ist das Gruppieren von Datensätzen nach einer Spalte. Sie haben zum Beispiel die Spalte "Klasse" und können nach dieser Spalte gruppieren, so dass Sie Datensätze erhalten, die nach den Werten dieser Spalte gruppiert sind.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X