Le WordPress d'aujourd'hui, décodé pour les développeurs

Performance

EXPLAIN ANALYZE sur une requête WordPress lente : lire le plan d’exécution

EXPLAIN ANALYZE, disponible depuis MySQL 8.0.18, donne un plan d'exécution réel et chiffré. Apprendre à le lire pour une requête générée par WP_Query.

Par WordPress Développement • 30 janvier 2021 • 4 min de lecture • Aucun commentaire
EXPLAIN ANALYZE sur une requête WordPress lente : lire le plan d'exécution

EXPLAIN ANALYZE SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts ... — poser cette instruction devant une requête générée par WP_Query change complètement ce qu’on peut observer, par rapport à un simple EXPLAIN. Depuis MySQL 8.0.18, EXPLAIN ANALYZE exécute réellement la requête, et associe à chaque étape du plan un temps mesuré et un nombre de lignes effectivement parcouru, plutôt qu’une simple estimation basée sur les statistiques de la table.

Cette différence compte énormément sur WordPress, où les statistiques de tables comme wp_postmeta peuvent se désynchroniser de la réalité après une longue période d’insertions et de suppressions massives, faussant les estimations d’un EXPLAIN classique sans que rien ne le signale explicitement.

Ce que EXPLAIN seul ne montre pas

Un EXPLAIN classique donne, pour chaque table impliquée, une estimation du nombre de lignes qui seront examinées, calculée à partir des statistiques stockées par l’optimiseur. Ces statistiques sont mises à jour périodiquement, ou manuellement via ANALYZE TABLE, mais jamais en temps réel. Sur une table dont le contenu a beaucoup changé récemment, l’estimation peut s’éloigner fortement de la réalité, sans que l’affichage d’EXPLAIN ne le fasse remarquer autrement qu’implicitement.

Lire une sortie EXPLAIN ANALYZE

Le format de sortie se présente en arbre, chaque nœud décrivant une opération (accès à un index, jointure, tri) avec, entre parenthèses, le coût estimé, le temps réel jusqu’au premier résultat, le temps réel total, le nombre réel de lignes produites, et le nombre de boucles d’exécution de ce nœud.

-> Nested loop inner join  (cost=1245.32 rows=112) (actual time=0.089..14.221 rows=98 loops=1)
    -> Index range scan on wp_posts using type_status_date
       (cost=310.12 rows=340) (actual time=0.041..2.983 rows=298 loops=1)
    -> Filter: (wp_postmeta.meta_key = 'evenement_date')
       (cost=2.71 rows=1) (actual time=0.037..0.038 rows=0.33 loops=298)
L'essentiel à retenir : EXPLAIN ANALYZE exécute réellement la requête, contrairement à EXPLAIN seul ; Chaque ligne donne un temps réel et un nombre de lignes réel ; L'écart entre lignes estimées et lignes réelles trahit une statistique obsolète

Repérer l’écart entre estimation et réalité

Sur l’exemple précédent, l’estimation prévoyait 340 lignes issues de l’index de date, la réalité en a produit 298 : un écart modeste, acceptable. En revanche, le filtre sur meta_key exécuté 298 fois pour ne retenir en moyenne que 0,33 ligne par exécution révèle un vrai problème : une jointure sur métadonnées qui filtre après coup plutôt qu’à la source, souvent le signe d’un index composite mal utilisé ou absent sur meta_key et meta_value combinés.

Le nombre de boucles, un indicateur souvent ignoré

La colonne loops mérite une attention particulière : un temps réel de 0,038 milliseconde répété 298 fois représente plus de 11 millisecondes cumulées, un montant qui n’apparaît nulle part si l’on ne regarde que le temps unitaire affiché pour ce nœud.

Une méthode de lecture en trois passes

  • Repérer d’abord le nœud racine, dont le temps réel total correspond au temps global de la requête.
  • Descendre ensuite vers les nœuds dont l’écart entre lignes estimées et lignes réelles est le plus important.
  • Multiplier le temps unitaire par le nombre de boucles pour chaque nœud suspect, avant de conclure à un problème.

Limiter le coût de l’analyse elle-même

Contrairement à EXPLAIN qui ne fait qu’estimer, EXPLAIN ANALYZE exécute réellement la requête analysée. Sur une requête d’écriture, cela signifie que l’opération a bel et bien lieu : il est donc essentiel de ne jamais lancer EXPLAIN ANALYZE devant une requête UPDATE ou DELETE en production sans l’avoir d’abord encapsulée dans une transaction annulée volontairement, sous peine de modifier réellement les données pendant ce qui devait rester un simple diagnostic.

START TRANSACTION;
EXPLAIN ANALYZE UPDATE wp_postmeta SET meta_value = 'test' WHERE meta_id = 12345;
ROLLBACK;

Comparer deux plans avant et après un index

La méthode la plus convaincante pour valider qu’un nouvel index résout réellement un problème consiste à capturer le plan EXPLAIN ANALYZE avant sa création, puis à le comparer ligne par ligne au plan obtenu après. Sur la requête étudiée ici, le temps réel total du nœud racine est passé de 14,221 millisecondes à 0,412 milliseconde après correction de l’index composite, une preuve chiffrée bien plus solide qu’une simple impression de rapidité perçue.

En résumé

EXPLAIN ANALYZE transforme un exercice souvent approximatif — deviner pourquoi une requête WP_Query traîne — en une lecture chiffrée et vérifiable. La discipline à adopter consiste à toujours croiser le temps unitaire d’un nœud avec son nombre de boucles avant de désigner un coupable, faute de quoi on risque d’optimiser la mauvaise partie de la requête.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi