Question

La sortie d’explication 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 exactement ce que vous voulez expliquer ou au moins me diriger vers une bonne ressource?

Était-ce utile?

La solution

Explaining_EXPLAIN.pdf pourrait également aider.

Autres conseils

La partie que j'ai toujours trouvée déroutante est le coût de démarrage par rapport au coût total. Je le fais chaque fois que je l'oublie, 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 trouvé dans la documentation de Postgres EXPLAIN , expliqué tel que je le comprends.

Voici un exemple tiré 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 le détail des coûts.)

Le coût est représenté sous forme de tuple, par exemple. le coût de LIMIT est de cost=0.00..3.39 et celui de l'analyse séquentielle post est de cost=0.00..15629.12. Le premier chiffre du tuple est le coût de démarrage et le second est le coût total . Parce que j’ai utilisé EXPLAIN ANALYZE et non Seq Scan, ces coûts sont des estimations et non des mesures réelles.

  • Le coût de démarrage est un concept délicat. Il ne s'agit pas simplement de la quantité de temps écoulé avant que ce composant ne démarre . Il représente la durée entre le moment où le composant commence à s'exécuter (lecture des données) et le moment où le composant affiche sa première ligne .
  • Le coût total correspond à la totalité du temps d'exécution du composant, du moment où il commence à lire les données à la fin de l'écriture de sa sortie.

Comme complication, chaque " parent " Les coûts du nœud comprennent les coûts de ses nœuds enfants. Dans la représentation textuelle, l’arbre est représenté par une indentation, par ex. 3.39 est un noeud parent et 15629.12 est son enfant. Dans la représentation PgAdmin, les flèches pointent d’enfant à parent & # 8212; la direction du flux de données & # 8212; ce qui pourrait ê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 EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2; est bien inférieur au coût total de son enfant ORDER BY. Le coût total n'est pas inclus car un composant tel que 23283.24 n'a pas besoin de traiter l'intégralité de ses entrées. Voir l'exemple 23859.27 dans la documentation de Postgres <=> .

Dans l'exemple ci-dessus, l'heure de démarrage des deux composants est égale à zéro, car aucun des composants ne doit effectuer de traitement avant d'écrire des lignes: une analyse séquentielle lit la première ligne de la table et l'émet. Le <=> lit sa première ligne, puis l’émet.

Quand un composant doit-il effectuer beaucoup de traitement avant de pouvoir commencer à générer 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 <=> clause:

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

Une fois encore, l'analyse séquentielle sur <=> n'a aucun coût de démarrage: elle commence à générer des lignes immédiatement. Mais le tri a un coût de démarrage important <=> car il doit trier la table entière avant de pouvoir générer même une seule ligne . Le coût total du tri <=> n’est que légèrement supérieur au coût de démarrage, ce qui reflète le fait qu’une fois l’ensemble du jeu de données trié, les données triées peuvent être émises très rapidement.

Notez que l'heure de démarrage de <=> <=> est exactement égale à l'heure de démarrage du tri. Ce n'est pas parce que <=> lui-même a un temps de démarrage élevé. En réalité, le temps de démarrage est nul, mais <=> cumule tous les coûts enfants pour chaque parent. Le <=> temps de démarrage inclut donc tLa 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. Par exemple, notre <=> n'a aucun temps de démarrage, mais ce n'est pas évident à première vue. Pour cette raison, plusieurs autres personnes ont lié à explique.depesz.com , un outil créé par Hubert Lubaczewski (aka Depesz). ) qui aide à comprendre <=> par & # 8212; entre autres & # 8212; soustrayant les coûts pour les enfants des coûts pour les parents. Il mentionne d'autres complexités dans un court article de blog sur son outil.

Il s’exécute du plus indenté au moins indenté, et je crois du bas du plan au sommet. (Ainsi, s’il existe deux sections en retrait, celle qui se trouve le plus loin en bas de la page s’exécute d’abord, puis, quand elles se rencontrent, s’exécute, la règle les rejoignant s’exécute.)

L’idée est qu’à chaque étape, 1 ou 2 jeux de données arrivent et soient traités par une règle. S'il ne s'agit que d'un ensemble de données, cette opération est effectuée sur cet ensemble de données. (Par exemple, analysez un index pour déterminer les lignes souhaitées, filtrez un ensemble de données ou le trier.) Si deux sont réunies, les deux ensembles de données sont les deux éléments indentés plus loin, et ils sont joints par la règle que vous voyez. Le sens de la plupart des règles peut être raisonnablement facilement deviné (en particulier si vous avez déjà lu un grand nombre de plans explicatifs auparavant), mais vous pouvez essayer de vérifier des éléments individuels en consultant 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 il fournit suffisamment de contexte pour que vous puissiez généralement déterminer ce que vous voulez. Par exemple, considérons 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 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'index id_orderitem_productid en l'utilisant pour rechercher les lignes souhaitées orderitem, puis trie cet ensemble de données à l'aide d'un tri rapide (le tri utilisé changera si les données ne correspondent pas en RAM), puis met cela de côté.

Ensuite, il analyse orditematt_attributeid_idx pour rechercher les lignes souhaitées dans orderitemattribute puis trie cet ensemble de données à l'aide d'un tri rapide.

Il prend ensuite les deux jeux de données et les fusionne. (Une jointure de fusion est une sorte d’opération & "; Zipping &"; Elle parcourt les deux jeux de données triés en parallèle, en émettant la ligne jointe quand ils correspondent.)

Comme je l’ai dit, vous travaillez sur la partie interne du plan, de bas en haut.

Un outil d'assistance en ligne est également disponible, Depesz , qui mettra en évidence les éléments coûteux de l'analyse. les résultats sont.

en a également un, voici le résultats identiques , ce qui, à mon sens, permet de mieux cerner le problème est.

PgAdmin vous montrera une représentation graphique du plan expliqué. Basculer entre les deux peut vraiment vous aider à comprendre ce que signifie la représentation textuelle. Cependant, si vous voulez simplement savoir ce que vous allez faire, vous pourrez toujours utiliser l'interface graphique.

La

La documentation officielle de PostgreSQL fournit une explication détaillée et intéressante sur la façon de comprendre le résultat de l'explication. .

Si vous installez pgadmin, il existe un bouton Explain qui, outre la représentation textuelle, dessine des diagrammes illustrant ce qui se passe, montrant les filtres, les tris et les fusions que je trouve vraiment utiles pour voir ce qui se passe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top