EXPLAIN â Afficher le plan d'exĂ©cution d'une instruction
EXPLAIN [ (option
[, ...] ) ]instruction
oĂčoption
est : ANALYZE [boolean
] VERBOSE [boolean
] COSTS [boolean
] SETTINGS [boolean
] GENERIC_PLAN [boolean
] BUFFERS [boolean
] SERIALIZE [ { NONE | TEXT | BINARY } ] WAL [boolean
] TIMING [boolean
] SUMMARY [boolean
] MEMORY [boolean
] FORMAT { TEXT | XML | JSON | YAML }
Cette commande affiche le plan d'exĂ©cution que l'optimiseur de PostgreSQL engendre pour l'instruction fournie. Le plan d'exĂ©cution dĂ©crit le parcours de la (des) table(s) utilisĂ©e(s) dans la requĂȘte -- parcours sĂ©quentiel, parcours d'index, etc. -- . Si plusieurs tables sont rĂ©fĂ©rencĂ©es, il prĂ©sente Ă©galement les algorithmes de jointures utilisĂ©s pour rassembler les lignes issues des diffĂ©rentes tables.
La partie la plus importante de l'affichage concerne l'affichage des coûts
estimés d'exécution. Ils représentent l'estimation faite par le
planificateur des temps d'exĂ©cution de la requĂȘte (mesurĂ© en une unitĂ© de
coût arbitraire bien que conventionnellement ce sont des lectures de page
disque). Deux nombres sont affichés : le coût de démarrage, écoulé
avant que la premiÚre ligne soit renvoyée, et le coût d'exécution total,
nĂ©cessaire au renvoi de toutes les lignes. Pour la plupart des requĂȘtes, le
coût qui importe est celui d'exécution totale. Mais dans certains cas, tel
que pour une sous-requĂȘte dans la clause EXISTS
, le
planificateur choisira le coût de démarrage le plus court, et non celui
d'exĂ©cution totale (car, de toute façon, l'exĂ©cuteur s'arrĂȘte aprĂšs la
rĂ©cupĂ©ration d'une ligne). De mĂȘme, lors de la limitation des rĂ©sultats Ă
retourner par une clause LIMIT
, la planificateur
effectue une interpolation entre les deux coûts limites pour choisir le
plan réellement le moins coûteux.
L'option ANALYZE
impose l'exĂ©cution de la requĂȘte en
plus de sa planification. De ce fait, les statistiques d'exécution réelle
sont ajoutées à l'affichage, en incluant le temps total écoulé à chaque
nĆud du plan (en millisecondes) et le nombre total de lignes renvoyĂ©es.
C'est utile pour vérifier la véracité des informations fournies par le
planificateur.
Il ne faut pas oublier que l'instruction est réellement exécutée avec
l'option ANALYZE
. Bien qu'EXPLAIN
inhibe l'affichage des retours d'une commande SELECT
,
les autres effets de l'instruction sont présents. Si EXPLAIN
ANALYZE
doit ĂȘtre utilisĂ© sur une instruction
INSERT
, UPDATE
,
DELETE
, MERGE
, CREATE TABLE AS
ou
EXECUTE
sans que la commande n'affecte les données,
l'approche suivante peut ĂȘtre envisagĂ©e :
BEGIN; EXPLAIN ANALYZE ...; ROLLBACK;
ANALYZE
Exécute la commande et affiche les temps d'exécution réels et d'autres
statistiques. Ce paramÚtre est par défaut à FALSE
.
VERBOSE
Affiche des informations supplémentaires sur le plan. Cela inclut la
liste des colonnes en sortie pour chaque nĆud du plan, les noms
des tables et fonctions avec le nom du schéma, les labels des variables
dans les expressions avec des alias de tables et le nom de chaque
trigger pour lesquels les statistiques sont affichées. L'identifiant de
requĂȘte sera aussi affichĂ© si une requĂȘte a Ă©tĂ© Ă©valuĂ©e, voir compute_query_id pour plus de dĂ©tails. Ce paramĂštre est
par défaut à FALSE
.
COSTS
Inclut des informations sur le coût estimé au démarrage et au total de
chaque nĆud du plan, ainsi que le nombre estimĂ© de lignes et la
largeur estimĂ©e de chaque ligne. Ce paramĂštre est par dĂ©faut Ă
TRUE
.
GENERIC_PLAN
Autorise la requĂȘte Ă contenir des caractĂšres joker de placement
comme $1
, et génÚre un plan générique qui ne dépend
pas de ces paramĂštres.
Voir PREPARE
pour les dĂ©tails sur les plans gĂ©nĂ©riques et les types de requĂȘtes qui
acceptent des paramĂštres.
Ce paramĂštre ne peut pas ĂȘtre utilisĂ© en mĂȘme temps que
ANALYZE
. Il est Ă FALSE
par
défaut.
BUFFERS
Inclut des informations sur l'utilisation des tampons. Spécifiquement,
inclut le nombre de blocs partagés lus dans la cache, lus en dehors du
cache, modifiés et écrits, le nombre de blocs locaux lus dans le cache,
lus en dehors du cache, modifiés, et écrits, et le nombre de blocs
temporaires lus et écrits, et le temps passé à lire et écrire des blocs
dans les fichiers de données, dans les blocs locaux et dans les fichiers
temporaires (en millisecondes) si le paramÚtre track_io_timing est activé. Le terme
hit signifie que la lecture a
été évitée car le bloc se trouvait déjà dans le cache.
Les blocs partagés contiennent les données de tables et index
standards ; les blocs locaux contiennent les tables et index
temporaires ; les blocs temporaires contiennent les données de
travail Ă court terme, comme les tris, les hachages, les nĆuds
Materialize, et des cas similaires. Le nombre de blocs modifiés
(dirtied) indique le nombre de blocs précédemment
propres qui ont Ă©tĂ© modifiĂ©s par cette requĂȘte ; le nombre de
blocs écrits (written) indique le nombre de blocs
dĂ©jĂ modifiĂ©s qui a Ă©tĂ© enlevĂ© du cache pour ĂȘtre Ă©crit sur disque lors
de l'exĂ©cution de cette requĂȘte. Le nombre de blocs affichĂ©s pour un
nĆud de niveau supĂ©rieur inclut ceux utilisĂ©s par tous ses enfants. Dans
le format texte, seules les valeurs différentes de zéro sont affichées.
La valeur par défaut de ce paramÚtre est FALSE
.
SETTINGS
Inclut des informations sur les paramĂštres de configuration. Plus
prĂ©cisĂ©ment, inclut les options affectant l'optimisation des requĂȘtes et
qui ont des valeurs différentes de leur valeur par défaut. Sa valeur par
défaut est FALSE
.
SERIALIZE
Inclut des informations sur le coût de
sérialisation des données en sortie de la
requĂȘte, autrement dit la conversion en format texte ou binaire Ă
envoyer au client. Ceci peut ĂȘtre une part significative du temps
nĂ©cessaire pour l'exĂ©cution rĂ©guliĂšre d'une requĂȘte, si les fonctions
en sortie sont coûteuses ou si des valeurs duTOAST
doivent ĂȘtre rĂ©cupĂ©rĂ©es. Le comportement par dĂ©faut de
EXPLAIN
, SERIALIZE NONE
, ne
réalise pas ces conversions. Si SERIALIZE TEXT
ou SERIALIZE BINARY
est indiqué, les conversions
appropriées sont réalisées et le temps passé à le faire est mesuré
(sauf si TIMING OFF
est indiqué). Si l'option
BUFFERS
est aussi indiqué, alors tout accÚs au
cache impliqué dans les conversions est aussi compté. Cependant,
en aucun cas, EXPLAIN
n'enverra les données
résultantes au client ; de ce fait, les coûts de transmission sur le
rĂ©seau ne peuvent pas ĂȘtre investiguĂ©s de cette façon. La sĂ©rialisation
peut seulement ĂȘtre activĂ©e quand ANALYZE
est aussi
activé. Si SERIALIZE
est écrit sans argument,
TEXT
est la valeur utilisée.
WAL
Inclut des informations sur les génération des enregistrements dans les
WAL. Spécifiquement, inclut le nombre d'enregistrements, le nombre
d'images complÚte de bloc (FPI), et la quantité d'octets générés dans
les WAL. Dans le format texte, seules les valeurs différentes de zéro
seront affichĂ©es. Ce paramĂštre peut seulement aussi ĂȘtre utilisĂ© quand
ANALYZE
est aussi activé. Il vaut par défaut
FALSE
.
TIMING
Inclut le temps rĂ©el de dĂ©marrage et le temps rĂ©el passĂ© dans le nĆud en
sortie. La surcharge de la lecture répétée de l'horloge systÚme peut
ralentir la requĂȘte de façon significative sur certains systĂšmes, et
donc il est utile de pouvoir configurer ce paramĂštre Ă
FALSE
quand seuls le décompte réel des lignes est
nécessaire. La durée d'exécution complÚte de la commande est toujours
mesurĂ©e, mĂȘme si le chronomĂ©trage des nĆuds est dĂ©sactivĂ© avec cette
option. Ce paramĂštre peut seulement ĂȘtre utilisĂ© quand l'option
ANALYZE
est aussi activée. La valeur par défaut est
TRUE
.
SUMMARY
Inclut des informations résumées (par exemple : information de temps
total) aprĂšs le plan de la requĂȘte. Les informations rĂ©sumĂ©es sont
inclues par défaut quand ANALYZE
est utilisé mais
sinon ne sont pas inclues par dĂ©faut, mais peuvent ĂȘtre activĂ©es avec
cette option. Le temps de planification dans EXPLAIN
EXECUTE
inclut le temps nécessaire pour récupérer le plan du
cache ainsi que le temps nécessaire pour le replanifier, si nécessaire.
MEMORY
Inclut des informations sur la consommation mémoire par la phase
d'optimisation de la requĂȘte. Plus spĂ©cifiquement, inclut la quantitĂ©
précise de stockage utilisé par l'optimiseur pour les structures en
mémoire, ainsi qu'un total de mémoire. Ce paramÚtre vaut par défaut
FALSE
.
FORMAT
Indique le format de sortie. Il peut valoir TEXT, XML, JSON ou YAML.
Toutes les sorties contiennent les mĂȘmes informations, mais les
programmes pourront plus facilement traiter les sorties autres que TEXT.
Ce paramÚtre est par défaut à TEXT
.
boolean
SpĂ©cifie si l'option sĂ©lectionnĂ©e doit ĂȘtre activĂ©e ou dĂ©sactivĂ©e. Vous
pouvez écrire TRUE
, ON
ou
1
pour activer l'option, et FALSE
,
OFF
ou 0
pour la désactiver. La
valeur de type boolean
peut
aussi ĂȘtre omise, auquel cas la valeur sera TRUE
.
instruction
Toute instruction SELECT
, INSERT
,
UPDATE
, DELETE
,
MERGE
,
VALUES
, EXECUTE
,
DECLARE
, CREATE TABLE AS
ou
CREATE MATERIALIZED VIEW AS
dont le plan d'exécution
est souhaité.
La sortie de la commande est une description textuelle du plan sélectionné
pour la requĂȘte
, annotée en
option des statistiques d'exécution. Section 14.1 décrit
les informations fournies.
Pour permettre au planificateur de requĂȘtes de
PostgreSQL de prendre des décisions en étant
raisonnablement informĂ© pour l'optimisation des requĂȘtes, les donnĂ©es du
catalogue pg_statistic
doivent ĂȘtre Ă jour pour toutes les tables utilisĂ©es dans la requĂȘte.
Habituellement, le démon autovacuum s'en
chargera automatiquement. Mais si une table a eu récemment des changements
importants dans son contenu, vous pourriez avoir besoin de lancer un
ANALYZE
manuel plutĂŽt
que d'attendre que l'autovacuum s'occupe des modifications.
Pour mesurer le coĂ»t d'exĂ©cution de chaque nĆud dans le plan d'exĂ©cution,
l'implémentation actuelle de la commande EXPLAIN ANALYZE
ajoute une surcharge de profilage Ă l'exĂ©cution de la requĂȘte. En rĂ©sultat,
exécuter EXPLAIN ANALYZE
sur une requĂȘte peut parfois
prendre un temps significativement plus long que l'exĂ©cution de la requĂȘte.
La durĂ©e supplĂ©mentaire dĂ©pend de la nature de la requĂȘte ainsi que de la
plateforme utilisĂ©e. Le pire des cas survient pour les nĆuds du plan
nĂ©cessitant en eux-mĂȘme peu de durĂ©e d'exĂ©cution par exĂ©cution et sur les
machines disposant d'appels systĂšmes relativement lents pour obtenir
l'heure du jour.
Afficher le plan d'une requĂȘte simple sur une table d'une seule colonne de
type integer
et 10000 lignes :
EXPLAIN SELECT * FROM foo; QUERY PLAN --------------------------------------------------------- Seq Scan on foo (cost=0.00..155.00 rows=10000 width=4) (1 row)
Voici le mĂȘme plan, mais formatĂ© avec JSON :
EXPLAIN (FORMAT JSON) SELECT * FROM foo; QUERY PLAN -------------------------------- [ + { + "Plan": { + "Node Type": "Seq Scan",+ "Relation Name": "foo", + "Alias": "foo", + "Startup Cost": 0.00, + "Total Cost": 155.00, + "Plan Rows": 10000, + "Plan Width": 4 + } + } + ] (1 row)
S'il existe un index et que la requĂȘte contient une condition
WHERE
indexable, EXPLAIN
peut
afficher un plan différent :
EXPLAIN SELECT * FROM foo WHERE i = 4; QUERY PLAN -------------------------------------------------------------- Index Scan using fi on foo (cost=0.00..5.98 rows=1 width=4) Index Cond: (i = 4) (2 rows)
Voici le mĂȘme plan, mais formatĂ© avec YAML :
EXPLAIN (FORMAT YAML) SELECT * FROM foo WHERE i='4'; QUERY PLAN ------------------------------- - Plan: + Node Type: "Index Scan" + Scan Direction: "Forward"+ Index Name: "fi" + Relation Name: "foo" + Alias: "foo" + Startup Cost: 0.00 + Total Cost: 5.98 + Plan Rows: 1 + Plan Width: 4 + Index Cond: "(i = 4)" (1 row)
L'obtention du format XML est laissé en exercice au lecteur.
Voici le mĂȘme plan avec les coĂ»ts supprimĂ©s :
EXPLAIN (COSTS FALSE) SELECT * FROM foo WHERE i = 4; QUERY PLAN ---------------------------- Index Scan using fi on foo Index Cond: (i = 4) (2 rows)
Exemple de plan de requĂȘte pour une requĂȘte utilisant une fonction d'agrĂ©gat :
EXPLAIN SELECT sum(i) FROM foo WHERE i < 10; QUERY PLAN --------------------------------------------------------------------- Aggregate (cost=23.93..23.93 rows=1 width=4) -> Index Scan using fi on foo (cost=0.00..23.92 rows=6 width=4) Index Cond: (i < 10) (3 rows)
Exemple d'utilisation de EXPLAIN EXECUTE
pour afficher
le plan d'exĂ©cution d'une requĂȘte prĂ©parĂ©e :
PREPARE query(int, int) AS SELECT sum(bar) FROM test WHERE id > $1 AND id < $2 GROUP BY foo; EXPLAIN ANALYZE EXECUTE query(100, 200); QUERY PLAN ------------------------------------------------------------------------------------- HashAggregate (cost=10.77..10.87 rows=10 width=12) (actual time=0.043..0.044 rows=10 loops=1) Group Key: foo Batches: 1 Memory Usage: 24kB -> Index Scan using test_pkey on test (cost=0.29..10.27 rows=99 width=8) (actual time=0.009..0.025 rows=99 loops=1) Index Cond: ((id > 100) AND (id < 200)) Planning Time: 0.244 ms Execution Time: 0.073 ms (7 rows)
Il est évident que les nombres présentés ici dépendent du contenu effectif
des tables impliquées. De plus, les nombres, et la stratégie sélectionnée
elle-mĂȘme, peuvent diffĂ©rer en fonction de la version de
PostgreSQL du fait des améliorations apportées
au planificateur. Il faut également savoir que la commande
ANALYZE
calcule les statistiques des données à partir
d'extraits aléatoires ; il est de ce fait possible que les coûts
estimĂ©s soient modifiĂ©s aprĂšs l'exĂ©cution de cette commande, alors mĂȘme la
distribution réelle des données dans la table n'a pas changé.
Notez que l'exemple précédent montrait un plan « personnalisé »
pour les valeurs spécifiques des paramÚtres données dans
EXECUTE
. Nous pourrions aussi souhaiter voir le plan
gĂ©nĂ©rique pour une requĂȘte Ă paramĂštre, ce qui peut se faire avec
GENERIC_PLAN
:
EXPLAIN (GENERIC_PLAN) SELECT sum(bar) FROM test WHERE id > $1 AND id < $2 GROUP BY foo; QUERY PLAN -------------------------------------------------------------------â------------ HashAggregate (cost=26.79..26.89 rows=10 width=12) Group Key: foo -> Index Scan using test_pkey on test (cost=0.29..24.29 rows=500 width=8) Index Cond: ((id > $1) AND (id < $2)) (4 rows)
Dans ce cas, l'analyseur détecte correctement que $1
et $2
devraient avoir le mĂȘme type de donnĂ©es que
id
, donc la manque d'information sur le type de
paramĂštre par PREPARE
n'était pas un problÚme. Dans
d'autres cas, il pourrait ĂȘtre nĂ©cessaire de spĂ©cifier explicitement les
types pour les symboles des paramĂštres, ce qui peut se faire en les
convertissant. Par exemple :
EXPLAIN (GENERIC_PLAN) SELECT sum(bar) FROM test WHERE id > $1::integer AND id < $2::integer GROUP BY foo;
L'instruction EXPLAIN
n'est pas définie dans le standard
SQL.
La syntaxe suivante était utilisée avant la version 9.0 de PostgreSQL et est toujours acceptée :
EXPLAIN [ ANALYZE ] [ VERBOSE ] requete
Notez que, dans cette syntaxe, les options doivent ĂȘtre indiquĂ©es dans l'ordre exact affichĂ©.