Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie gruppiert man richtig in MySQL?

Als erstes muss klargestellt werden, dass SQL nicht MySQL ist.

In Standard-SQL ist es nicht erlaubt, nach einer Teilmenge der nicht aggregierten Felder zu gruppieren. Der Grund ist sehr einfach. Angenommen, ich führe diese Abfrage aus:

SELECT color, owner_name, COUNT(*) FROM cars
GROUP BY color

Diese Abfrage würde keinen Sinn machen. Selbst der Versuch, es zu erklären, wäre unmöglich. Sicher ist es, Farben auszuwählen und die Anzahl der Autos pro Farbe zu zählen. Es fügt jedoch auch den owner_name hinzu Feld und es kann viele Besitzer für eine bestimmte Farbe geben, wie es im Fall von White der Fall ist Farbe. Also, wenn es viele owner_name geben kann Werte für eine einzelne color das zufällig das einzige Feld in GROUP BY ist Klausel... dann welcher owner_name zurückgesendet?

Wenn es erforderlich ist, einen owner_name zurückzugeben dann sollten einige Kriterien hinzugefügt werden, um nur eines davon auszuwählen, z. B. das alphabetisch erste, was in diesem Fall John wäre . Dieses Kriterium würde zum Hinzufügen einer Aggregatfunktion MIN(owner_name) führen und dann macht die Abfrage wieder Sinn, da sie zumindest nach allen nicht aggregierten Feldern in der select-Anweisung gruppiert.

Wie Sie sehen, gibt es einen klaren und praktischen Grund dafür, dass Standard-SQL bei der Gruppierung unflexibel ist. Andernfalls könnten Sie in unangenehme Situationen geraten, in denen der Wert für eine Spalte unvorhersehbar ist, und das ist kein nettes Wort, insbesondere wenn die ausgeführte Abfrage Ihre Bankkontotransaktionen anzeigt.

Abgesehen davon, warum sollte MySQL dann Abfragen zulassen, die möglicherweise keinen Sinn ergeben? Und noch schlimmer, der Fehler in der obigen Abfrage könnte nur syntaktisch erkannt werden! Die kurze Antwort lautet:Leistung. Die lange Antwort lautet, dass es bestimmte Situationen gibt, in denen, basierend auf Datenbeziehungen, das Erhalten eines unvorhersehbaren Werts von der Gruppe zu einem vorhersagbaren Wert führt.

Wenn Sie es noch nicht herausgefunden haben, können Sie den Wert, den Sie erhalten, wenn Sie ein unvorhersehbares Element aus einer Gruppe nehmen, nur dann vorhersagen, wenn alle Elemente in der Gruppe gleich sind. Ein klares Beispiel für diese Situation ist die Beispielabfrage in derselben Frage. Sehen Sie sich an, wie owner_id und owner_name bezieht sich auf die Tabelle. Es ist klar, dass eine gegebene owner_id , z.B. 2 , können Sie nur einen eindeutigen owner_name haben . Selbst wenn Sie viele Zeilen haben, erhalten Sie Mike, indem Sie eine auswählen als Ergebnis. Im formalen Datenbankjargon kann dies als owner_id erklärt werden bestimmt funktional owner_name .

Schauen wir uns diese voll funktionsfähige MySQL-Abfrage genauer an:

SELECT owner_id, owner_name, COUNT(*) total FROM cars
GROUP BY owner_id

Bei einer beliebigen owner_id dies würde denselben owner_name zurückgeben , also fügen Sie es zu GROUP BY hinzu -Klausel führt nicht dazu, dass mehr Zeilen zurückgegeben werden. Sogar das Hinzufügen einer aggregierten Funktion MAX(owner_name) führt nicht dazu, dass weniger Zeilen zurückgegeben werden. Die resultierenden Daten sind genau die gleichen. In beiden Fällen würde die Abfrage sofort in eine legale Standard-SQL-Abfrage umgewandelt, da zumindest alle nicht aggregierten Felder gruppiert würden. Es gibt also 3 Ansätze, um die gleichen Ergebnisse zu erzielen.

Wie ich bereits erwähnt habe, hat diese nicht standardmäßige Gruppierung jedoch einen Leistungsvorteil. Sie können diesen so unterschätzten Link überprüfen in dem dies ausführlicher erklärt wird, aber ich werde den wichtigsten Teil zitieren:

Erwähnenswert ist, dass die Ergebnisse nicht zwangsläufig falsch sind sondern unbestimmt . Mit anderen Worten, das Erhalten der erwarteten Ergebnisse bedeutet nicht, dass Sie die richtige Abfrage geschrieben haben. Wenn Sie die richtige Abfrage schreiben, erhalten Sie immer die erwarteten Ergebnisse.

Wie Sie sehen, könnte es sich lohnen, diese MySQL-Erweiterung auf GROUP BY anzuwenden Klausel. Wie dem auch sei, falls dies noch nicht 100 % klar ist, gibt es eine Faustregel, die sicherstellt, dass Ihre Gruppierung immer korrekt ist:Gruppieren Sie immer mindestens nach allen nicht aggregierten Feldern in der Auswahlklausel . In bestimmten Situationen verschwenden Sie möglicherweise einige CPU-Zyklen, aber es ist besser, als unbestimmt zurückzugeben Ergebnisse. Wenn Sie immer noch Angst haben, nicht korrekt zu gruppieren, ändern Sie den ONLY_FULL_GROUP_BY Der SQL-Modus könnte ein letzter Ausweg sein :)

Möge Ihre Gruppierung korrekt und performant sein... oder zumindest korrekt.