Wie funktioniert ORDER BY FIELD () in MySQL intern?


37

Ich verstehe, wie ORDER BYKlausel funktioniert und wie die FIELD()Funktion funktioniert. Ich möchte verstehen, wie beide zusammenarbeiten, um zu sortieren. Wie werden die Zeilen abgerufen und wie wird die Sortierreihenfolge abgeleitet?

+----+---------+
| id |  name   |
+----+---------+
|  1 | stan    |
|  2 | kyle    |
|  3 | kenny   |
|  4 | cartman |
+----+---------+ 

SELECT * FROM mytable WHERE id IN (3,2,1,4) ORDER BY FIELD(id,3,2,1,4)

Die obige Abfrage führt zu

+----+---------+
| id |  name   |
+----+---------+
|  3 | kenny   |
|  2 | kyle    |
|  1 | stan    |
|  4 | cartman |
+----+---------+ 

etwas ähnliches wie ORDER BY 3, 2, 1, 4

FRAGEN

  • Wie funktioniert das intern?
  • Wie erhält MySQL die Zeilen und berechnet die Sortierreihenfolge?
  • Woher weiß MySQL, dass es nach der ID-Spalte sortieren muss?

1
Probieren Sie diese Variante Ihrer Abfrage aus: SELECT *, FIELD(id,3,2,1,4) AS f FROM mytable WHERE id IN (3,2,1,4);Fügen Sie dann ORDER BY foder hinzu ORDER BY FIELD(id,3,2,1,4)und versuchen Sie es erneut.
ypercubeᵀᴹ

Antworten:


64

Für die Aufzeichnung

SELECT * FROM mytable WHERE id IN (1,2,3,4) ORDER BY FIELD(id,3,2,1,4);

sollte auch funktionieren, da Sie die Liste in der WHEREKlausel nicht bestellen müssen

Wie es funktioniert,

  • FIELD () ist eine Funktion, die die Indexposition einer durch Kommas getrennten Liste zurückgibt, wenn der gesuchte Wert existiert.

  • Die ORDER BYWerte werden von dem ausgewertet, was FIELD () zurückgibt

Sie können alle Arten von ausgefallenen Bestellungen erstellen

Zum Beispiel mit der Funktion IF ()

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0),FIELD(id,3,2,1,4);

Dadurch werden die ersten 4 IDs oben in der Liste angezeigt. Andernfalls wird sie unten angezeigt. Warum?

In der ORDER BYerhält man entweder 0 oder 1.

  • Wenn die erste Spalte 0 ist, lassen Sie eine der ersten 4 IDs erscheinen
  • Wenn die erste Spalte 1 ist, lassen Sie sie danach erscheinen

Lassen Sie es uns mit DESC in der ersten Spalte spiegeln

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0) DESC,FIELD(id,3,2,1,4);

In der ORDER BYerhält man entweder noch 0 oder 1.

  • Wenn die erste Spalte 1 ist, stellen Sie sicher, dass nur die ersten 4 IDs angezeigt werden.
  • Wenn die erste Spalte 0 ist, lassen Sie die ersten 4 IDs in der ursprünglichen Reihenfolge erscheinen

IHRE AKTUELLE FRAGE

Wenn Sie diesbezüglich ernsthafte Interna wünschen, lesen Sie die Seiten 189 und 192 des Buches

MySQL-Interna

für einen tiefen tauchgang.

Im Wesentlichen gibt es eine C ++ - Klasse namens ORDER *order(Der ORDER BYAusdrucksbaum). In JOIN::prepare, *orderwird in einer aufgerufenen Funktion verwendet setup_order(). Warum mitten in der JOINKlasse? Jede Abfrage, auch eine Abfrage für eine einzelne Tabelle, wird immer als JOIN verarbeitet. (Siehe meinen Beitrag. Gibt es einen Ausführungsunterschied zwischen einer JOIN-Bedingung und einer WHERE-Bedingung? )

Der Quellcode für all das ist sql/sql_select.cc

Offensichtlich wird der ORDER BYBaum die Bewertung von enthalten FIELD(id,3,2,1,4). Somit sind die Zahlen 0, 1, 2, 3, 4 die Werte, die sortiert werden, während ein Verweis auf die betreffende Zeile geführt wird.


1
Dies ist eine hervorragende Erklärung. Mit diesen Methoden konnte ich 3 Befehle erhalten, einen primären ersten Wert, der das Maximum der Menge ist, dann nach FELD und dann nach einer anderen Spalte für diejenigen, die nicht in der FELD-Menge enthalten sind. Etwas, wovon ich vor einiger Zeit nicht geträumt hätte. Vielen Dank, dass Sie sich die Zeit genommen haben, um wirklich zu erklären, wie dies tatsächlich funktioniert.
Lizardx

Angenommen, es gibt NWerte in beiden INund FIELD. In diesem Beispiel N=4. Verstehe ich richtig, dass diese Abfrage mindestens ~N^2Vorgänge ausführen wird. Weil bei jeder FIELDBerechnung ~Nfür jede Zeile ein Vergleich durchgeführt wird. Wenn ja, ist das ziemlich langsam für große NVielleicht ist es kein sehr guter Ansatz?
Gherman

@Gherman Die FIELD()Funktion sollte eine O(1)Operation sein, da FIELD()sie einen numerischen Index hat id. Ich sehe also nichts anderes als O(n)Zeilen. Ich sehe FIELD()keine iterative Operation, wie GREATEST()sie nötig wäre.
RolandoMySQLDBA

@RolandoMySQLDBA Mein Punkt ist , dass , wenn FIELDhat NArgumente zu vergleichen , dann wird es ausführen NVergleiche. Wie kann es sonst passieren, dass eine Nummer mit Nanderen Nummern verglichen wird, wenn dies nicht der Fall ist O(N)? Die einzige Möglichkeit, die ich mir vorstellen kann, ist eine Art Optimierung durch eine spezielle Datenstruktur wie einen Hash oder einen Baum von Argumenten. Eigentlich weiß ich, dass INdas eine solche Optimierung hat. Ich weiß es nicht FIELD. Was meinen Sie mit einem "numerischen Index"?
Gherman

1
Hey @RaymondNijland, die CASE-Anweisung ist verständlicher. In diesem Fall hat der syntaktische Zucker nur weniger Schriftzug.
RolandoMySQLDBA

1

Vielleicht ist dies zu weit vom eigentlichen Code entfernt, so dass es nicht niedrig genug von dem ist, was Sie wollten:

Wenn MySQL den Index nicht zum Abrufen von Daten in sortierter Reihenfolge verwenden kann, erstellt es eine temporäre Tabelle / Ergebnismenge mit allen ausgewählten Spalten und einigen zusätzlichen Daten. Eine davon ist eine Art Spalte zum Speichern der Ergebnisse des ORDER BY-Ausdruckswerts für jede Zeile. dann sendet er diese tmp-Tabelle an einen "filesort" -Rutine mit Informationen, nach welcher Spalte sortiert werden soll. Danach sind die Zeilen in sortierter Reihenfolge, sodass sie einzeln ausgewählt und ausgewählte Spalten zurückgegeben werden können.


Diese Erklärung berücksichtigt nicht, wie die FIELDFunktion berechnet wird. Ich befürchte, dass dies erhebliche Auswirkungen auf die Leistung haben könnte.
Gherman

@ Gherman Ich glaube nicht, es sei denn, Sie verwenden eine sehr lange Liste von Argumenten (da die Funktion linear zur Anzahl der Argumente ist . Der Datenzugriff ist eine Größenordnung langsamer als einfache Vergleiche.
Jkavalik

Ja, lange Liste von Argumenten. In diesem Beispiel gibt es so viele Argumente wie Datensätze.
Gherman

Ich würde nur Hunderte oder Tausende als so viele bezeichnen, und dann bekommst du sowieso andere Probleme (
Abfragegröße

warum nicht hunderte ergebnisse? Ist es viele
Gherman
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.