Comment fonctionne ORDER BY FIELD () dans MySQL et qui fonctionne en interne


37

Je comprends comment ORDER BYfonctionne la clause et comment FIELD()fonctionne la fonction. Ce que je veux comprendre, c'est comment les deux travaillent ensemble pour trier. Comment les lignes sont-elles récupérées et comment l’ordre de tri est-il dérivé?

+----+---------+
| 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)

La requête ci-dessus entraînera

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

quelque chose de similaire à dire ORDER BY 3, 2, 1, 4

DES QUESTIONS

  • Comment ça marche en interne?
  • Comment MySQL obtient-il les lignes et calcule-t-il l'ordre de tri?
  • Comment MySQL sait-il qu'il doit trier par la colonne id?

1
essayez cette variante de votre requête: SELECT *, FIELD(id,3,2,1,4) AS f FROM mytable WHERE id IN (3,2,1,4);Ajoutez ensuite ORDER BY fou ORDER BY FIELD(id,3,2,1,4)et essayez à nouveau.
ypercubeᵀᴹ

Réponses:


64

Pour le compte rendu

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

devrait fonctionner aussi bien parce que vous n'avez pas à commander la liste dans la WHEREclause

Quant à la façon dont cela fonctionne,

  • FIELD () est une fonction qui renvoie la position d'index d'une liste délimitée par des virgules si la valeur recherchée existe.

  • Les ORDER BYvaleurs sont évaluées par ce que FIELD () renvoie

Vous pouvez créer toutes sortes de commandes fantaisies

Par exemple, en utilisant le IF () fonction

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);

Les 4 premiers identifiants apparaîtront en haut de la liste. Sinon, ils apparaîtront en bas. Pourquoi?

Dans le ORDER BY, vous obtenez 0 ou 1.

  • Si la première colonne est 0, indiquez l’un des 4 premiers identifiants
  • Si la première colonne est 1, faites-la apparaître après

Retournons-le avec DESC dans la première colonne

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);

Dans le ORDER BY, vous obtenez toujours 0 ou 1.

  • Si la première colonne est 1, indiquez autre chose que les 4 premiers identifiants.
  • Si la première colonne est 0, les 4 premiers identifiants apparaissent dans l'ordre d'origine

VOTRE QUESTION RÉELLE

Si vous voulez sérieusement des problèmes internes à ce sujet, passez aux pages 189 et 192 du livre.

MySQL Internals

pour une vraie plongée profonde.

En substance, il existe une classe C ++ appelée ORDER *order(l' ORDER BYarbre d'expression). Dans JOIN::prepare, *orderest utilisé dans une fonction appelée setup_order(). Pourquoi au milieu de la JOINclasse? Chaque requête, même une requête sur une seule table, est toujours traitée comme une jointure (voir mon post. Existe-t-il une différence d'exécution entre une condition JOIN et une condition WHERE? )

Le code source pour tout cela est sql/sql_select.cc

Évidemment, l’ ORDER BYarbre va contenir l’évaluation de FIELD(id,3,2,1,4). Ainsi, les nombres 0,1,2,3,4 sont les valeurs en train d'être triées en portant une référence à la ligne concernée.


1
C'est une excellente explication. En utilisant ces méthodes, j'ai pu obtenir 3 commandes, une première valeur primaire qui est le maximum de l'ensemble, puis par le champ, puis par une autre colonne pour celles qui ne font pas partie du champ. Quelque chose dont je n'aurais pas rêvé il y a quelque temps. Merci d'avoir pris le temps d'expliquer réellement comment cela fonctionne.
Lizardx

Supposons qu'il y ait des Nvaleurs dans les deux INet FIELD. Dans cet exemple N=4. Dois-je bien comprendre que cette requête va effectuer au moins des ~N^2opérations. Parce que chaque FIELDcalcul fait des ~Ncomparaisons une fois pour chaque ligne. Si c'est le cas, c'est assez lent pour les gros NPeut-être que ce n'est pas une très bonne approche?
Gherman

@Gherman La FIELD()fonction doit être une O(1)opération car FIELD()a un index numérique id. Donc, je ne vois rien d'autre que O(n)basé sur des lignes. Je ne vois FIELD()aucune opération itérative comme GREATEST()il faudrait.
RolandoMySQLDBA

@RolandoMySQLDBA Mon point est que si FIELDa des Narguments avec lesquels comparer, alors il exécutera des Ncomparaisons. Sinon, comment va-t-il comparer un nombre avec d' Nautres si on ne le fait pas O(N)? La seule possibilité à laquelle je puisse penser est une sorte d'optimisation via une structure de données spéciale telle qu'un hachage ou une arborescence d'arguments. En fait, je sais que INcela a une telle optimisation. Je ne sais pas pour FIELD. Qu'entendez-vous par "index numérique"?
Gherman

1
Hey @RaymondNijland, L’instruction CASE est plus compréhensible. Pour ce cas, le sucre syntaxique a moins d’écriture.
RolandoMySQLDBA

1

Peut-être que ce sera trop loin du code réel, donc pas assez bas de ce que vous vouliez:

Lorsque MySQL ne peut pas utiliser index pour extraire les données dans un ordre trié, il crée une table / un ensemble de résultats temporaire avec toutes les colonnes sélectionnées et des données supplémentaires - une de celles-ci est une sorte de colonne permettant de stocker les résultats de la valeur de l'expression ORDER BY pour chaque ligne - puis il envoie cette table tmp à un rutine "filesort" avec des informations sur la colonne à trier. Après cela, les lignes sont triées de manière à pouvoir les sélectionner une à une et renvoyer les colonnes sélectionnées.


Cette explication ne prend pas en compte la manière dont la FIELDfonction est calculée. Je crains que cela puisse avoir un impact significatif sur les performances.
Gherman

@Gherman Je ne le pense pas, à moins que vous n'utilisiez une très longue liste d'arguments (car la fonction est linéaire par rapport au nombre d'arguments . L'accès aux données est un ordre de grandeur plus lent que les simples comparaisons.
jkavalik

Oui, longue liste d'arguments. Il y a autant d'arguments que d'enregistrements dans cet exemple.
Gherman

Je n’étiqueterais que des centaines, voire des milliers, autant, et vous auriez quand même d’autres problèmes (taille de la requête, etc.)
jkavalik

pourquoi pas des centaines de résultats? Est-ce que c'est beaucoup?
Gherman
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.