Qu'est-ce que PostgreSQL m'explique exactement?

116

La sortie explicative de MySQL est assez simple. PostgreSQL est un peu plus compliqué. Je n'ai pas été en mesure de trouver une bonne ressource qui l'explique non plus.

Pouvez-vous décrire ce que dit exactement ce que dit ou au moins me diriger vers une bonne ressource?

kjg
la source

Réponses:

50

Explaining_EXPLAIN.pdf pourrait également vous aider.

Milen A. Radev
la source
65
Je ne sais pas pourquoi les gens pensent que les diaporamas constituent une bonne documentation technique. Une vidéo de la conférence pourrait être utile, mais la densité d'informations de cette diapositive est très proche de zéro. Dans les six premières diapositives (1/5 du total), il y a exactement 1 phrase de contenu technique: "• EXPLAIN fonctionne sur n'importe quel DML et pas seulement SELECT (c'est-à-dire UPDATE, DELETE et INSERT)". Mon plus gros malentendu est ce que signifie le temps de «démarrage», et cela n'est expliqué nulle part dans ces ~ 30 diapositives.
Mark E. Haase
80

La partie que j'ai toujours trouvée déroutante est le coût de démarrage par rapport au coût total. Je cherche ça sur Google à chaque fois que j'oublie ça, ce qui me ramène ici, ce qui n'explique pas la différence, c'est pourquoi j'écris cette réponse. C'est ce que j'ai glané dans la documentation PostgresEXPLAIN , expliqué comme je le comprends.

Voici un exemple d'une application qui gère un forum:

EXPLAIN SELECT * FROM post LIMIT 50;

Limit  (cost=0.00..3.39 rows=50 width=422)
  ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

Voici l'explication graphique de PgAdmin:

explication graphique de la première requête

(Lorsque vous utilisez PgAdmin, vous pouvez pointer votre souris sur un composant pour lire les détails du coût.)

Le coût est représenté par un tuple, par exemple le coût du LIMITis cost=0.00..3.39et le coût du balayage séquentiel postest cost=0.00..15629.12. Le premier nombre du tuple est le coût de démarrage et le second le coût total . Parce que j'ai utilisé EXPLAINet non EXPLAIN ANALYZE, ces coûts sont des estimations, pas des mesures réelles.

  • Le coût de démarrage est un concept délicat. Cela ne représente pas seulement la durée avant le démarrage de ce composant . Il représente le laps de temps entre le moment où le composant commence à s'exécuter (lecture des données) et le moment où le composant sort sa première ligne .
  • Le coût total correspond à la durée totale d'exécution du composant, depuis le moment où il commence la lecture des données jusqu'à la fin de l'écriture de sa sortie.

En guise de complication, les coûts de chaque nœud «parent» comprennent les coûts de ses nœuds enfants. Dans la représentation textuelle, l'arbre est représenté par une indentation, par exemple LIMITest un nœud parent etSeq Scan est son enfant. Dans la représentation PgAdmin, les flèches pointent de l'enfant au parent - la direction du flux de données - ce qui peut être contre-intuitif si vous êtes familier avec la théorie des graphes.

La documentation indique que les coûts incluent tous les nœuds enfants, mais notez que le coût total du parent 3.39est beaucoup plus petit que le coût total de son enfant 15629.12. Le coût total n'est pas inclusif car un composant comme celui LIMIT-ci n'a pas besoin de traiter l'intégralité de son entrée. Voir l' EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2;exemple dans la documentation PostgresEXPLAIN .

Dans l'exemple ci-dessus, le temps de démarrage est nul pour les deux composants, car aucun des deux composants n'a besoin d'effectuer de traitement avant de commencer à écrire des lignes: une analyse séquentielle lit la première ligne de la table et l'émet. Le LIMITlit sa première ligne puis l'émet.

Quand un composant doit-il effectuer beaucoup de traitements avant de pouvoir commencer à produire des lignes? Il y a beaucoup de raisons possibles, mais regardons un exemple clair. Voici la même requête d'avant mais contenant maintenant une ORDER BYclause:

EXPLAIN SELECT * FROM post ORDER BY body LIMIT 50;

Limit  (cost=23283.24..23283.37 rows=50 width=422)
  ->  Sort  (cost=23283.24..23859.27 rows=230412 width=422)
        Sort Key: body
        ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

Et graphiquement:

explication graphique de la deuxième requête

Encore une fois, le balayage séquentiel postn'a aucun coût de démarrage: il commence immédiatement à produire des lignes. Mais le tri a un coût de démarrage important 23283.24car il doit trier la table entière avant de pouvoir produire ne serait-ce qu'une seule ligne . Le coût total du tri 23859.27n'est que légèrement supérieur au coût de démarrage, reflétant le fait qu'une fois l'ensemble de données trié, les données triées peuvent être émises très rapidement.

Notez que l'heure de démarrage de LIMIT 23283.24est exactement égale à l'heure de démarrage du tri. Ce n'est pas parce que LIMITlui - même a un temps de démarrage élevé. Il n'a en fait aucun temps de démarrage en soi, mais EXPLAINcumule tous les coûts enfants pour chaque parent, de sorte que leLIMIT temps de démarrage inclut la somme des temps de démarrage de ses enfants.

Ce cumul des coûts peut rendre difficile la compréhension du coût d'exécution de chaque composant individuel. Par exemple, notre LIMITtemps de démarrage est nul, mais ce n'est pas évident à première vue. Pour cette raison, plusieurs autres personnes se sont connectées à Expliquer.depesz.com , un outil créé par Hubert Lubaczewski (alias depesz) qui aide à comprendre EXPLAIN, entre autres, en soustrayant les coûts des enfants des coûts des parents. Il mentionne d'autres complexités dans un court article de blog sur son outil.

Mark E. Haase
la source
4
Merci pour ça. Je voudrais également ajouter un visualiseur d'explication qui fait un travail encore meilleur d'affichage de la sortie (imo). tatiyants.com/pev
Jonathan Porter
Très bonne réponse. Et votre commentaire selon lequel le coût de démarrage comprend le temps de retour de la première ligne m'a aidé à comprendre pourquoi le coût de démarrage pour le tri n'était pas seulement 15629.12.
Joel Wigton le
43

Il s'exécute du plus indenté au moins indenté, et je crois du bas du plan vers le haut. (Donc, s'il y a deux sections en retrait, l'une plus en bas de la page s'exécute en premier, puis quand elles se rencontrent, les autres s'exécute, alors la règle qui les rejoint s'exécute.)

L'idée est qu'à chaque étape, il y a 1 ou 2 ensembles de données qui arrivent et sont traités par une règle. S'il s'agit d'un seul ensemble de données, cette opération est effectuée sur cet ensemble de données. (Par exemple, parcourez un index pour déterminer les lignes que vous voulez, filtrez un ensemble de données ou triez-le.) Si deux, les deux ensembles de données sont les deux éléments qui sont plus indentés et ils sont joints par la règle que vous voyez. La signification de la plupart des règles peut être raisonnablement facilement devinée (en particulier si vous avez déjà lu un tas de plans d'explication auparavant), mais vous pouvez essayer de vérifier des éléments individuels soit en regardant dans la documentation ou (plus facilement) en jetant simplement la phrase dans Google avec quelques mots clés comme EXPLAIN.

Ce n'est évidemment pas une explication complète, mais cela fournit suffisamment de contexte pour que vous puissiez généralement comprendre ce que vous voulez. Par exemple, considérez ce plan à partir d'une base de données réelle:

explain analyze
select a.attributeid, a.attributevalue, b.productid
from orderitemattribute a, orderitem b
where a.orderid = b.orderid
and a.attributeid = 'display-album'
and b.productid = 'ModernBook';

------------------------------------------------------------------------------------------------------------------------------------------------------------

 Merge Join  (cost=125379.14..125775.12 rows=3311 width=29) (actual time=841.478..841.478 rows=0 loops=1)
   Merge Cond: (a.orderid = b.orderid)
   ->  Sort  (cost=109737.32..109881.89 rows=57828 width=23) (actual time=736.163..774.475 rows=16815 loops=1)
         Sort Key: a.orderid
         Sort Method:  quicksort  Memory: 1695kB
         ->  Bitmap Heap Scan on orderitemattribute a  (cost=1286.88..105163.27 rows=57828 width=23) (actual time=41.536..612.731 rows=16815 loops=1)
               Recheck Cond: ((attributeid)::text = 'display-album'::text)
               ->  Bitmap Index Scan on (cost=0.00..1272.43 rows=57828 width=0) (actual time=25.033..25.033 rows=16815 loops=1)
                     Index Cond: ((attributeid)::text = 'display-album'::text)
   ->  Sort  (cost=15641.81..15678.73 rows=14769 width=14) (actual time=14.471..16.898 rows=1109 loops=1)
         Sort Key: b.orderid
         Sort Method:  quicksort  Memory: 76kB
         ->  Bitmap Heap Scan on orderitem b  (cost=310.96..14619.03 rows=14769 width=14) (actual time=1.865..8.480 rows=1114 loops=1)
               Recheck Cond: ((productid)::text = 'ModernBook'::text)
               ->  Bitmap Index Scan on id_orderitem_productid  (cost=0.00..307.27 rows=14769 width=0) (actual time=1.431..1.431 rows=1114 loops=1)
                     Index Cond: ((productid)::text = 'ModernBook'::text)
 Total runtime: 842.134 ms
(17 rows)

Essayez de le lire par vous-même et voyez si cela a du sens.

Ce que j'ai lu, c'est que la base de données analyse d'abord l' id_orderitem_productidindex, en l'utilisant pour trouver les lignes à partir desquelles elle veut orderitem, puis trie cet ensemble de données à l'aide d'un tri rapide (le tri utilisé changera si les données ne rentrent pas dans la RAM), puis le met de côté.

Ensuite, il scanne orditematt_attributeid_idxpour trouver les lignes à partir desquelles il veut orderitemattribute, puis trie cet ensemble de données à l'aide d'un tri rapide.

Il prend ensuite les deux ensembles de données et les fusionne. (Une jointure par fusion est une sorte d'opération de "compression" dans laquelle elle parcourt les deux ensembles de données triés en parallèle, émettant la ligne jointe lorsqu'ils correspondent.)

Comme je l'ai dit, vous travaillez de la partie intérieure du plan à la partie extérieure, de bas en haut.

utilisateur11318
la source
22

Il existe également un outil d'aide en ligne, Depesz , qui mettra en évidence où se trouvent les parties coûteuses des résultats d'analyse.

a également un, voici les mêmes résultats , qui pour moi permettent de mieux comprendre où se trouve le problème.

Stephen Denne
la source
20
Expliquer-analyser.info semble être en panne, mais je suis d'accord pour dire qu'expliquer.depesz.com est très utile.
benvolioT
13

PgAdmin vous montrera une représentation graphique du plan d'explication. Basculer entre les deux peut vraiment vous aider à comprendre ce que signifie la représentation textuelle. Cependant, si vous voulez juste savoir ce qu'il va faire, vous pourrez peut-être toujours utiliser l'interface graphique.

Grant Johnson
la source
0

Si vous installez pgadmin, il y a un bouton Explain qui, en plus de donner la sortie texte, dessine des diagrammes de ce qui se passe, montrant les filtres, les tris et les fusions de sous-ensembles que je trouve vraiment utiles pour voir ce qui se passe.

Greg
la source