Wie verarbeitet MySQL ORDER BY und LIMIT in einer Abfrage?

251

Ich habe eine Abfrage, die so aussieht:

SELECT article FROM table1 ORDER BY publish_date LIMIT 20

Wie funktioniert ORDER BY? Wird es alle Datensätze bestellen und dann die ersten 20 erhalten, oder wird es 20 Datensätze erhalten und sie nach publish_dateFeld sortieren?

Wenn es der letzte ist, ist nicht garantiert, dass Sie wirklich die neuesten 20 Artikel erhalten.

Alex
quelle
6
Beachten Sie, dass wenn einige publish_dates gleich sind, die Reihenfolge nach ihnen keine bestimmten Ergebnisse liefert. Wenn Sie sie LIMITfür die Paginierung verwenden, erhalten Sie möglicherweise dieselben Elemente auf verschiedenen Seiten!
Konrad Morawski

Antworten:

244

Es wird zuerst bestellt, dann die ersten 20. Eine Datenbank verarbeitet auch alles in der WHEREvorherigen Klausel ORDER BY.

James
quelle
1
Das Timing ist also dasselbe?
Yasar Arafath
7
Falsch! LIMITbricht ORDER BY. Mit LIMITeinem ORDER BYfalschen Ergebnis. LIMITordnet irgendwie die Ergebnismenge neu, die vonORDER BY
Green
6
@ Green, du liegst falsch. Lesen Sie dies für die Erklärung: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html Wenn die Spalte ORDER BY indiziert ist, werden möglicherweise Datensätze in einer anderen Reihenfolge als ohne LIMIT zurückgegeben, wenn mehr vorhanden sind als 1 Datensätze mit demselben Wert in dieser Spalte.
Yitwail
1
Eine schnelle Lösung für solche Probleme besteht darin, der Reihenfolge eine weitere Spalte hinzuzufügen, indem vorzugsweise eindeutige Werte verwendet werden, damit die Datenbank eine konsistente Regel für die Reihenfolge von Zeilen erhält, wenn der Wert der ersten Reihenfolge nach Spalte für mehrere Zeilen gleich ist.
Rineez
37

Die LIMIT-Klausel kann verwendet werden, um die Anzahl der von der SELECT-Anweisung zurückgegebenen Zeilen zu beschränken. LIMIT verwendet ein oder zwei numerische Argumente, die beide nichtnegative Ganzzahlkonstanten sein müssen (außer bei Verwendung vorbereiteter Anweisungen).

Bei zwei Argumenten gibt das erste Argument den Versatz der ersten zurückzugebenden Zeile und das zweite die maximale Anzahl der zurückzugebenden Zeilen an. Der Versatz der ersten Zeile ist 0 (nicht 1):

SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15

Um alle Zeilen von einem bestimmten Versatz bis zum Ende der Ergebnismenge abzurufen, können Sie für den zweiten Parameter eine große Zahl verwenden. Diese Anweisung ruft alle Zeilen von der 96. bis zur letzten Zeile ab:

SELECT * FROM tbl LIMIT 95,18446744073709551615;

Mit einem Argument gibt der Wert die Anzahl der Zeilen an, die vom Anfang der Ergebnismenge zurückgegeben werden sollen:

SELECT * FROM tbl LIMIT 5; # Retrieve first 5 rows

Mit anderen Worten, LIMIT row_count entspricht LIMIT 0, row_count.

Alle Details unter: http://dev.mysql.com/doc/refman/5.0/en/select.html

bensiu
quelle
Ruft es nicht die Zeilen 5-14 ab?
Adonis K. Kakoulidis
@adonis Nein, ist es nicht. Das Beispiel ist direkt aus der MySQL-Dokumentation
dcaswell
Nummer 5 ist die 6. Reihe. 5 Zeilen (0 bis 4) werden ignoriert.
Phil Perry
1
Die Verwendung von LIMIT ohne ORDER BY kann jedoch zu inkonsistenten Ergebnissen führen! Leider muss die gesamte Ergebnismenge bestellt werden, bevor das LIMIT angewendet wird, oder das DBMS kann das Ergebnis willkürlich ordnen und dann OFFSET und LIMIT für diese Menge. Ich habe gelesen, dass dies möglicherweise daran liegt, dass das DBMS einen alternativen Abfrageplan basierend auf OFFSET und LIMIT auswählt, also in beliebiger Reihenfolge.
Barton
4
Frage ist das Limit & Order by. Aber die Antwort hat überhaupt nichts mit dieser Frage zu tun
Shen Liang
9

Genau wie @James sagt, werden alle Datensätze sortiert und dann die ersten 20 Zeilen abgerufen.

Da dies der Fall ist, erhalten Sie garantiert die 20 zuerst veröffentlichten Artikel, die neueren werden nicht angezeigt.

In Ihrer Situation, empfehle ich Ihnen , fügen Sie desczu order by publish_date, wenn Sie die neuesten Artikel wollen, dann werden die neuesten Artikel zuerst sein.

Wenn Sie das Ergebnis in aufsteigender Reihenfolge halten möchten und dennoch nur die 10 neuesten Artikel möchten, können Sie mysql bitten, Ihr Ergebnis zweimal zu sortieren.

Diese Abfrage unten sortiert das Ergebnis absteigend und begrenzt das Ergebnis auf 10 (das ist die Abfrage in Klammern). Es wird weiterhin in absteigender Reihenfolge sortiert, und wir sind damit nicht zufrieden. Deshalb bitten wir mysql, es noch einmal zu sortieren. Jetzt haben wir das neueste Ergebnis in der letzten Zeile.

select t.article 
from 
    (select article, publish_date 
     from table1
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

Wenn Sie alle Spalten benötigen, geschieht dies folgendermaßen:

select t.* 
from 
    (select * 
     from table1  
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

Ich verwende diese Technik, wenn ich manuell Abfragen schreibe, um die Datenbank auf verschiedene Dinge zu untersuchen. Ich habe es nicht in einer Produktionsumgebung verwendet, aber jetzt, wenn ich es als Benchmark markiert habe, wirkt sich die zusätzliche Sortierung nicht auf die Leistung aus.

emanciperingsivraren
quelle
2
Ihre zusätzliche Sortierung kann praktisch keinen messbaren Einfluss auf die Leistung haben, da sie auf nur 10 Zeilen / Elemente beschränkt ist :-). Im Allgemeinen ist das Sortieren einer In-Memory-Tabelle (die von einer Unterauswahl erstellt wird) sehr schnell und kaum messbar, es sei denn, Sie haben Millionen von Zeilen oder das DBMS paginiert die Ergebnismenge auf die Festplatte, da sie nicht in den Speicher passt (in diesem Fall) Abhängig vom DBMS kann die Abfrage auch abgebrochen werden.
Martin Kersten
7

Wenn es einen geeigneten Index gibt, in diesem Fall auf dem publish_dateFeld, muss MySQL nicht den gesamten Index scannen, um die 20 angeforderten Datensätze zu erhalten - die 20 Datensätze werden am Anfang des Index gefunden. Wenn jedoch kein geeigneter Index vorhanden ist, ist ein vollständiger Scan der Tabelle erforderlich.

Dazu gibt es einen MySQL Performance Blog-Artikel aus dem Jahr 2009.

Martin Clayton
quelle
7

Sie können am Ende der Bestellung [asc] oder [desc] hinzufügen, um die frühesten oder neuesten Datensätze zu erhalten

Auf diese Weise erhalten Sie beispielsweise zuerst die neuesten Datensätze

ORDER BY stamp DESC

Fügen Sie die LIMITKlausel nachORDER BY

Paul
quelle
3
Willkommen beim Stackoverflow. Ich denke, Sie haben die Frage möglicherweise falsch verstanden. Ich glaube, sie fragten eher nach der Reihenfolge der Operationen als nach der Art der Sortierung. (Aber es ist strittig, da die Frage bereits vor einiger Zeit beantwortet wurde;)
Leigh
5

Sie können diesen Code verwenden, SELECT article FROM table1 ORDER BY publish_date LIMIT 0,10 wobei 0 ein Startlimit für den Datensatz und 10 für den Datensatz ist

gaurangkathiriya
quelle
8
Nein, das ist nicht erforderlich . LIMIT 10ist eine Abkürzung für LIMIT 0,10.
Lawrence Dol
2
ja, nicht erforderlich für LIMIT 0,10, aber Sie können Like This Limit 10,20
gaurangkathiriya
3

LIMIT wird normalerweise als letzte Operation angewendet, sodass das Ergebnis zuerst sortiert und dann auf 20 begrenzt wird. Tatsächlich wird die Sortierung beendet, sobald die ersten 20 sortierten Ergebnisse gefunden werden.

Egor Pavlikhin
quelle
11
Dein zweiter Satz geht gegen deinen ersten. Die Sortierung kann nicht beendet werden, wenn die ersten 20 Ergebnisse gefunden wurden, da die Sortierung wie gesagt erfolgt, bevor die Ergebnisse zurückgegeben werden. MySQL kann erst nach Abschluss der Sortierung die ersten 20 Ergebnisse ermitteln.
Tom
@ Tom, eigentlich kann es, wenn nach einer indizierten Spalte bestellt. Es wird hier erklärt: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
yitwail
-3

Auch die Syntax von LIMIT unterscheidet sich je nach Datenbank, zum Beispiel:

mysql - GRENZWERT 1, 2

postgres - LIMIT 2 OFFSET 1

Harish Sharma
quelle