Pourquoi SELECT * serait-il plus rapide que SELECT foo?

28

Considérons un tableau de valeurs et de hachages, comme ceci:

+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| val        | char(9)  | NO   |     | NULL    |                |
| val_hashed | char(50) | YES  |     | NULL    |                |
+------------+----------+------+-----+---------+----------------+

La requête suivante se termine en 0,00 secondes:

SELECT * FROM hashes ORDER BY 1 DESC LIMIT 1;

Cependant, cette requête prend 3 min 17 secondes:

SELECT val FROM hashes ORDER BY 1 DESC LIMIT 1;

Je vois que pendant que la requête est en cours d'exécution, la liste des processus l'affiche comme état Sorting result. La situation est parfaitement reproductible. Notez qu'un autre processus effectue des INSERTopérations sur la table en continu.

Pourquoi la requête plus spécifique prendrait-elle plus de temps à s'exécuter que la *requête? J'ai toujours pensé que les *requêtes devaient être évitées spécifiquement pour des raisons de performances.

dotancohen
la source
7
Les premières instructions utilisent probablement l'index de clé primaire idpour trouver la première ligne. Le second doit trier le résultat complet dans la valcolonne (non indexée) .
a_horse_with_no_name
8
La ORDER BY NUMBERsyntaxe est assez sujette aux erreurs.
usr
2
Ajout à votre dernier commentaire, SELECT *combiné avec un index de colonne dans ORDER BYest obscurcissant quelle colonne est triée - une autre raison d'éviter *s ...
lc.
@lc., Que voulez-vous dire?
Pacerier
@Pacerier Je veux dire que ce *n'est pas explicite. Donc dire "donnez-moi toutes les colonnes et triez par la troisième" est à peu près aussi déterministe que dire "allez au supermarché et dites-moi combien de feux vous avez passés"
lc.

Réponses:

33

La phrase ORDER BY 1fait référence à différentes colonnes; dans le premier, ce sera iddans le second val. Puisque idc'est la clé, elle sera indexée etorder by sera une quantité de travail insignifiante. Pour order by val, cependant, le système devra récupérer chaque ligne, trier le tableau complet par val, puis choisir une seule de ces lignes.

Changez les deux requêtes en order by idet je pense que vos temps d'exécution seront presque identiques.

Michael Green
la source
3
Parfois, les questions les plus délicates sont celles qui nous regardent juste en face. Merci, Michael!
dotancohen
7

La différence de performances dans votre requête est bien expliquée par MG. Je vais aborder ceci:

J'ai toujours pensé que les requêtes * devaient être évitées spécifiquement pour des raisons de performances.

select *ne comporte pas de sanctions particulières en soi, il est problématique lorsqu'il est mal utilisé. Dans une requête à table unique, cela fonctionne très bien. joignez maintenant cette table à une autre avec 20 colonnes, puis ajoutez des jointures à 5 autres tables avec plusieurs colonnes chacune. MAINTENANT, c'est un problème. Il en va de même pour les personnes qui enseignent un large pansement "ne faites jamais X" sans expliquer pourquoi.

Paul
la source
3
SELECT *peut être un problème même pour une requête à table unique. Par exemple, SELECT * FROM hashes ORDER BY val;fera probablement une analyse complète de la table, puis un tri tandis que SELECT val FROM hashes ORDER BY val;ne fera qu'une analyse complète de l'index, et aucun tri (en supposant qu'un index existe sur val). Ainsi, cela ne fait jamais de mal de ne sélectionner que les résultats dont nous avons besoin.
ypercubeᵀᴹ
Je suppose que vous avez vu ça? sqlblog.com/blogs/aaron_bertrand/archive/2009/10/10/…
Max Vernon
@ypercube, cela se produit-il même si our select(*)n'est utilisé qu'en tant que sous-sélection ? Puisqu'il s'agit d'une sélection intégrée, MySQL ne serait-il pas assez intelligent pour déterminer les colonnes réelles qui doivent être sélectionnées?
Pacerier
L'optimiseur @Pacerier mysql a différents niveaux de "smartness", selon la version que vous utilisez. En général, c'était assez stupide en ce qui concerne les sous-requêtes imbriquées, donc quoi que vous puissiez l'aider, c'était bien.
ypercubeᵀᴹ
@ypercube, Ah, si seulement c'est aussi intelligent que pgsql.
Pacerier