Pourquoi SELECT * est-il beaucoup plus rapide que de sélectionner toutes les colonnes (dans un ordre de colonnes différent) par nom?

12

Sur un tableau avec les colonnes a, b, c, d, e, f, g, h, i, j, k j'obtiens:

select * from misty order by a limit 25;
Time: 302.068 ms

Et:

select c,b,j,k,a,d,i,g,f,e,h from misty order by a limit 25;
Time: 1258.451 ms

Existe-t-il un moyen de rendre la sélection par colonne aussi rapide?

Mise à jour:

Aucun index sur une table, nouvellement créé

Voici le EXPLAIN ANALYZE, ne semble pas trop utile:

explain analyze select * from misty order by a limit 25;

Limit  (cost=43994.40..43994.46 rows=25 width=190) (actual time=404.958..404.971 rows=25 loops=1)
->  Sort  (cost=43994.40..45731.11 rows=694686 width=190) (actual time=404.957..404.963 rows=25 loops=1)
     Sort Key: a
     Sort Method: top-N heapsort  Memory: 28kB
     ->  Seq Scan on misty  (cost=0.00..24390.86 rows=694686 width=190) (actual time=0.013..170.945 rows=694686 loops=1)
Total runtime: 405.019 ms
(6 rows)

Et:

explain analyze select c,b,j,k,a,d,i,g,f,e,h from misty order by a limit 25;

Limit  (cost=43994.40..43994.46 rows=25 width=190) (actual time=1371.735..1371.745 rows=25 loops=1)
->  Sort  (cost=43994.40..45731.11 rows=694686 width=190) (actual time=1371.733..1371.736 rows=25 loops=1)
     Sort Key: a
     Sort Method: top-N heapsort  Memory: 28kB
     ->  Seq Scan on misty  (cost=0.00..24390.86 rows=694686 width=190) (actual time=0.015..516.355 rows=694686 loops=1)
Total runtime: 1371.797 ms
(6 rows)
Evgeny
la source
La colonne est-elle indexée? Pouvez-vous poster expliquer analyser?
user_0
1
Vous devez être prudent en faisant deux sélections de suite et en comparant les temps. Les données en cache sur la deuxième requête peuvent expliquer la différence de temps.
Walter Mitty,
1
Je vois aussi des différences, mais pas aussi prononcées. Ma table a des lignes = 514431 largeur = 215, et j'obtiens environ 1,5 s pour le select *cas et environ 2,2 s pour la sélection avec des colonnes répertoriées dans un ordre différent .
Colin 't Hart
Si je répertorie toutes les colonnes dans le même ordre que celui défini dans le tableau, j'obtiens approximativement les mêmes temps que si je le faisais select *.
Colin 't Hart,
2
Le titre est trompeur. La question est vraiment de savoir pourquoi la durée d'un tri dépend de l'ordre des colonnes de sortie.
Daniel Vérité

Réponses:

12

Cela a été publié sur la liste de diffusion pgsql-hackers et j'ai essayé d'y répondre brièvement. Il semble que si la liste cible (colonnes spécifiées) correspond exactement au descripteur de tuple de la relation, c'est-à-dire à la fois en nombre de colonnes et dans l'ordre, l'analyse sous-jacente peut renvoyer un tuple directement consommable par le nœud de tri englobant. D'un autre côté, si la liste cible ne correspond pas (dans l'ordre ou le nombre de colonnes spécifiées), l'analyse renvoie une forme de tuples qui nécessite l'étape de préparation des données de Sort pour effectuer un travail supplémentaire (conversion d'un format de tuple interne en le format directement consommable par le code de tri).

Soit dit en passant, «*» est transformé en interne en une liste qui correspond (intuitivement) au descripteur de tuple de la relation.

EDIT: Si vous regardez les temps réels de votre dernier EXPLAIN ANALYZE Seq Scan, vous pouvez voir que c'est plus que les anciens. Cela s'est produit parce que l'analyse a effectué une étape supplémentaire de projection (c'est-à-dire la conversion du tuple de segment de mémoire en un format de valeurs internes [], nulls []). Et parce que cela s'est produit, le nœud de tri supérieur a dû faire un travail supplémentaire dans son initialisation des données, celle de la reconvertir au format de tuple que l'étape de tri réelle comprend. Cela ressort clairement du coût de démarrage du tri. Cela ne se produit pas dans le premier cas. Autrement dit, à la fois l'analyse renvoie le tuple tel quel et l'étape d'initialisation du tri le copie simplement.

amitlan
la source
@ Colin'tHart, j'espère que cela a du sens.
amitlan
Oui. J'aurais espéré qu'il serait possible de sauter cette étape ou de la raccourcir en utilisant un "mélange de pointeurs", mais c'est une discussion pour pgsql-hackers.
Colin 't Hart,
Il peut y avoir quelques améliorations à l'horizon avec la récente relance du travail de classement des colonnes logiques.
amitlan
J'y pensais déjà et j'espère bien!
Colin 't Hart,
cher monsieur, si je n'ai besoin que de quelques colonnes au lieu de toutes, laquelle sera plus rapide? sélectionnez * ou sélectionnez some_of_columns? Merci beaucoup.
sgon00