Was ist schneller, SELECT DISTINCT oder GROUP BY in MySQL?

273

Wenn ich einen Tisch habe

CREATE TABLE users (
  id int(10) unsigned NOT NULL auto_increment,
  name varchar(255) NOT NULL,
  profession varchar(255) NOT NULL,
  employer varchar(255) NOT NULL,
  PRIMARY KEY  (id)
)

und ich möchte alle eindeutigen Werte des professionFeldes erhalten, was schneller (oder empfohlen) wäre:

SELECT DISTINCT u.profession FROM users u

oder

SELECT u.profession FROM users u GROUP BY u.profession

?

vava
quelle
2
Sie können so schnell selbst testen, wie Sie die Frage stellen. Irritierend ist, dass es fast unmöglich ist, ein Szenario zu konstruieren, in dem DISTINCT GROUP BY übertrifft - was ärgerlich ist, da dies eindeutig nicht der Zweck von GROUP BY ist. GROUP BY kann jedoch zu irreführenden Ergebnissen führen, was meiner Meinung nach Grund genug ist, dies zu vermeiden.
Erdbeere
Es gibt ein weiteres Duplikat mit einer anderen Antwort. siehe MySql - Distinct vs Group By <<< es heißt, GROUP BY ist besser
kolunar
Hier sehen Sie , ob Sie den Zeitunterschied zwischen DISTINCT und GROUP BY messen möchten, indem Sie Ihre Abfrage ausführen.
Kolunar

Antworten:

258

Sie sind im Wesentlichen einander äquivalent (tatsächlich implementieren einige Datenbanken dies DISTINCTunter der Haube).

Wenn einer von ihnen schneller ist, wird es sein DISTINCT. Dies liegt daran, dass ein Abfrageoptimierer, obwohl beide identisch sind, die Tatsache erfassen müsste, dass Sie GROUP BYkeine Gruppenmitglieder, sondern nur deren Schlüssel ausnutzen. DISTINCTmacht dies explizit, so dass Sie mit einem etwas dümmeren Optimierer davonkommen können.

Im Zweifelsfall testen!

SquareCog
quelle
76
DISTINCT ist nur dann schneller, wenn Sie keinen Index haben (da dieser nicht sortiert wird). Wenn Sie einen Index haben und dieser verwendet wird, sind dies Synonyme.
Quassnoi
9
Die Definition von DISTINCTund GROUP BYunterscheidet sich darin, dass DISTINCTdie Ausgabe nicht sortiert werden muss, und GROUP BYstandardmäßig. Doch in MySQL auch eine DISTINCT+ ORDER BYkönnte noch schneller sein als ein GROUP BYaufgrund der zusätzlichen Hinweise für den Optimierer , wie durch SquareCog erläutert.
Rustyx
1
DISTINCT ist bei großen Datenmengen viel schneller.
Pankaj Wanjari
7
Ich habe dies getestet und festgestellt, dass in einer indizierten Spalte, mysql, group by etwa 6x langsamer war als bei einer ziemlich komplizierten Abfrage. Fügen Sie dies einfach als Datenpunkt hinzu. Über 100.000 Zeilen. Testen Sie es und überzeugen Sie sich selbst.
Lizardx
siehe MySql - Distinct vs Group By <<< es heißt, GROUP BY ist besser
kolunar
100

Wenn Sie einen Index haben profession , sind diese beiden Synonyme.

Wenn Sie dies nicht tun, verwenden Sie DISTINCT .

GROUP BYin MySQLSorten Ergebnisse. Sie können sogar tun:

SELECT u.profession FROM users u GROUP BY u.profession DESC

und lassen Sie Ihre Berufe sortieren DESC ordnen .

DISTINCT Erstellt eine temporäre Tabelle und verwendet sie zum Speichern von Duplikaten. GROUP BYmacht das gleiche, sortiert aber danach die unterschiedlichen Ergebnisse.

Damit

SELECT DISTINCT u.profession FROM users u

ist schneller, wenn Sie keinen Index haben profession.

Quassnoi
quelle
6
Sie können hinzufügen , ORDER BY NULLum die GROUP BYdie Art zu vermeiden.
Ariel
Noch langsamer, selbst bei Gruppierung nach Null
Thanh Trung
@ThanhTrung: Was ist langsamer als was?
Quassnoi
@ Quassnoi Gruppe langsamer als deutlich, auch wenn Sortierung vermieden wird
Thanh Trung
Hinweis: Auftragsqualifizierer für GROUP BY waren in MySQL 8 veraltet.
Matthew Lenz
18

Alle obigen Antworten sind korrekt, für den Fall von DISTINCT in einer einzelnen Spalte gegenüber GROUP BY in einer einzelnen Spalte. Jede DB-Engine hat ihre eigene Implementierung und Optimierung. Wenn Sie sich (in den meisten Fällen) für den sehr geringen Unterschied interessieren, müssen Sie gegen einen bestimmten Server UND eine bestimmte Version testen! Da sich Implementierungen ändern können ...

ABER wenn Sie mehr als eine Spalte in der Abfrage auswählen, ist der DISTINCT wesentlich anders! In diesem Fall werden ALLE Spalten aller Zeilen anstelle nur einer Spalte verglichen.

Also, wenn Sie etwas haben wie:

// This will NOT return unique by [id], but unique by (id,name)
SELECT DISTINCT id, name FROM some_query_with_joins

// This will select unique by [id].
SELECT id, name FROM some_query_with_joins GROUP BY id

Es ist ein häufiger Fehler zu glauben, dass das Schlüsselwort DISTINCT Zeilen durch die erste von Ihnen angegebene Spalte unterscheidet, aber das Schlüsselwort DISTINCT ist auf diese Weise ein allgemeines Schlüsselwort.

Menschen, bei denen Sie darauf achten müssen, dass die obigen Antworten nicht in allen Fällen als richtig angesehen werden ... Sie könnten verwirrt sein und die falschen Ergebnisse erzielen, während Sie nur optimieren wollten!

daniel.gindi
quelle
3
Obwohl diese Frage ist etwa MySQL sollte beachtet werden , dass die zweite Abfrage funktioniert nur in MySQL. Nahezu jedes andere DBMS lehnt die zweite Anweisung ab, da der Operator GROUP BY ungültig verwendet wird.
a_horse_with_no_name
Nun, "fast" ist eine problematische Definition :-) Es wäre viel hilfreicher, wenn Sie ein bestimmtes DBMS angeben, das Sie getestet haben, um festzustellen , dass es einen Fehler für diese Anweisung generiert.
daniel.gindi
3
Postgres, Oracle, Firebird, DB2, SQL Server für den Anfang. MySQL: sqlfiddle.com/#!2/6897c/1 Postgres: sqlfiddle.com/#!12/6897c/1 Oracle: sqlfiddle.com/#!12/6897c/1 SQL Server: sqlfiddle.com/#!6/ 6897c / 1
a_horse_with_no_name
17

Entscheide dich für das Einfachste und Kürzeste, wenn du kannst - DISTINCT scheint mehr zu sein, als du suchst, nur weil es dir genau die Antwort gibt, die du brauchst und nur das!

Tim
quelle
7

Group by ist teurer als Distinct, da Group by eine Sortierung des Ergebnisses vornimmt, während die Unterscheidung dies vermeidet. Wenn Sie jedoch eine Gruppe erstellen möchten, die das gleiche Ergebnis wie eine eindeutige ergibt , geben Sie die Reihenfolge null an .

SELECT DISTINCT u.profession FROM users u

entspricht

SELECT u.profession FROM users u GROUP BY u.profession order by null
Ranjith
quelle
ist gleichSELECT profession FROM users GROUP BY profession
6

gut unterscheidbar kann langsamer sein als Gruppe durch in einigen Fällen in Postgres (weiß nicht über andere dbs).

getestetes Beispiel:

postgres=# select count(*) from (select distinct i from g) a;

count 

10001
(1 row)

Time: 1563,109 ms

postgres=# select count(*) from (select i from g group by i) a;

count
10001
(1 row)

Time: 594,481 ms

http://www.pgsql.cz/index.php/PostgreSQL_SQL_Tricks_I

also sei vorsichtig ... :)

OptilabWorker
quelle
5

Es scheint, dass die Abfragen nicht genau gleich sind. Zumindest für MySQL.

Vergleichen Sie:

  1. Beschreiben Sie einen ausgewählten Produktnamen aus northwind.products
  2. Beschreiben Sie den ausgewählten Produktnamen aus der Gruppe northwind.products nach Produktnamen

Die zweite Abfrage gibt zusätzlich "Using filesort" in Extra.

amartynov
quelle
1
Sie sind in Bezug auf das, was sie bekommen, gleich, nicht in Bezug darauf, wie sie es bekommen. Ein idealer Optimierer würde sie auf die gleiche Weise ausführen, aber der MySQL-Optimierer ist nicht ideal. Basierend auf Ihren Beweisen scheint es, dass DISTINCT schneller gehen würde - O (n) gegen O (n * log n).
SquareCog
Also ist "using filesort" im Wesentlichen eine schlechte Sache?
Vava
In diesem Fall ist es so, weil Sie nicht sortieren müssen (Sie würden, wenn Sie die Gruppen benötigen). MySQL sortiert, um dieselben Einträge zusammenzufügen, und erhält dann Gruppen, indem die sortierte Datei gescannt wird. Sie brauchen nur Unterscheidungsmerkmale, also müssen Sie nur Ihre Schlüssel hashen, während Sie einen einzelnen Tabellenscan durchführen.
SquareCog
1
Fügen Sie ORDER BY NULLder GROUP BYVersion hinzu und sie werden gleich sein.
Ariel
3

In MySQL verwendet " Group By" einen zusätzlichen Schritt : filesort. Mir ist klar, dass DISTINCTes schneller ist als GROUP BY, und das war eine Überraschung.

Carlos
quelle
3

Nach intensiven Tests kamen wir zu dem Schluss, dass GROUP BY schneller ist

SELECT sql_no_cache opnamegroep_intern FROM telwerken WHERE opnemergroepIN (7,8,9,10,11,12,13) ​​Gruppe nach opnamegroep_intern

635 totaal 0,0944 Sekunden Weergave van Records 0 - 29 (635 totaal, Abfrage duurde 0,0484 Sek.)

SELECT sql_no_cache different (opnamegroep_intern) FROM telwerken WHERE opnemergroepIN (7,8,9,10,11,12,13)

635 totaal 0,2117 Sekunden (fast 100% langsamer) Weergave van zeichnet 0 - 29 auf (635 totaal, Abfrage duurde 0,3468 Sek.)

Mürrisch
quelle
2

(eher eine funktionale Anmerkung)

Es gibt Fälle, in denen Sie GROUP BY verwenden müssen, beispielsweise wenn Sie die Anzahl der Mitarbeiter pro Arbeitgeber ermitteln möchten:

SELECT u.employer, COUNT(u.id) AS "total employees" FROM users u GROUP BY u.employer

In einem solchen Szenario DISTINCT u.employerfunktioniert das nicht richtig. Vielleicht gibt es einen Weg, aber ich weiß es einfach nicht. (Wenn jemand weiß, wie man eine solche Abfrage mit DISTINCT macht, fügen Sie bitte eine Notiz hinzu!)

Ivan Dossev
quelle
2

Hier ist ein einfacher Ansatz, bei dem die 2 verschiedenen verstrichenen Zeiten für jede Abfrage gedruckt werden.

DECLARE @t1 DATETIME;
DECLARE @t2 DATETIME;

SET @t1 = GETDATE();
SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT
SET @t2 = GETDATE();
PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar);

SET @t1 = GETDATE();
SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY
SET @t2 = GETDATE();
PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar);

ODER versuchen Sie SET STATISTICS TIME (Transact-SQL)

SET STATISTICS TIME ON;
SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT
SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY
SET STATISTICS TIME OFF;

Es zeigt einfach die Anzahl der Millisekunden an, die erforderlich sind, um jede Anweisung wie folgt zu analysieren, zu kompilieren und auszuführen:

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 2 ms.
kolunar
quelle
1

Dies ist keine Regel

Versuchen Sie es für jede Abfrage separat und gruppieren Sie dann nach ... vergleichen Sie die Zeit, um jede Abfrage abzuschließen und die schnellere zu verwenden ....

In meinem Projekt verwende ich manchmal group by und andere unterscheiden

user2832991
quelle
0

Wenn Sie keine Gruppenfunktionen ausführen müssen (Summe, Durchschnitt usw., wenn Sie der Tabelle numerische Daten hinzufügen möchten), verwenden Sie SELECT DISTINCT. Ich vermute, es ist schneller, aber ich habe nichts zu zeigen.

Wenn Sie sich Gedanken über die Geschwindigkeit machen, erstellen Sie auf jeden Fall einen Index für die Spalte.

tehvan
quelle
0

SELECT DISTINCT ist immer gleich oder schneller als ein GROUP BY. Auf einigen Systemen (z. B. Oracle) ist es möglicherweise so optimiert, dass es für die meisten Abfragen mit DISTINCT identisch ist. Bei anderen (z. B. SQL Server) kann dies erheblich schneller sein.

Piep Piep
quelle
0

Wenn das Problem dies zulässt, versuchen Sie es mit EXISTS, da es so optimiert ist, dass es endet, sobald ein Ergebnis gefunden wird (und keine Antwort puffert). Wenn Sie also nur versuchen, Daten für eine WHERE-Klausel wie diese zu normalisieren

SELECT FROM SOMETHING S WHERE S.ID IN ( SELECT DISTINCT DCR.SOMETHING_ID FROM DIFF_CARDINALITY_RELATIONSHIP DCR ) -- to keep same cardinality

Eine schnellere Antwort wäre:

SELECT FROM SOMETHING S WHERE EXISTS ( SELECT 1 FROM DIFF_CARDINALITY_RELATIONSHIP DCR WHERE DCR.SOMETHING_ID = S.ID )

Dies ist nicht immer möglich, aber wenn verfügbar, sehen Sie eine schnellere Antwort.

Daniel R.
quelle