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

Performance

Un CHU et ses 100 000 pages : l’index qui manquait à la recherche

Huit secondes pour retrouver une fiche par spécialité sur un intranet hospitalier de 100 000 pages. La cause n'était pas le plugin de recherche, mais une table MySQL sans index composite.

Par Clément Hadrot • 31 mai 2020 • 4 min de lecture • Aucun commentaire
Un CHU et ses 100 000 pages : l'index qui manquait à la recherche

Huit secondes. C’est le temps que mettait l’intranet d’un centre hospitalier universitaire à afficher les résultats d’une recherche par spécialité médicale, sur une base de 100 000 pages de fiches pratiques, protocoles et annuaires de services. Le personnel soignant, qui consulte ces fiches en situation d’urgence entre deux patients, n’a pas le temps d’attendre huit secondes pour retrouver un protocole.

La première hypothèse, la plus intuitive, pointait vers le moteur de recherche WordPress natif, réputé peu performant sur de gros volumes. Un plugin de recherche tierce avait même été envisagé pour remplacer la requête WP_Query par défaut. L’audit a révélé une cause bien plus précise, et bien moins coûteuse à corriger.

Le diagnostic : EXPLAIN ne ment jamais

Avant de changer de moteur de recherche, la requête SQL générée par WordPress a été isolée via Query Monitor, puis rejouée directement en base avec le préfixe EXPLAIN. Le résultat était sans appel : la requête, qui filtrait simultanément sur une métadonnée de spécialité (stockée dans wp_postmeta) et sur le statut de publication, effectuait un type: ALL, c’est-à-dire un scan complet de la table, faute d’index exploitable sur cette combinaison de colonnes.

EXPLAIN SELECT p.ID FROM wp_posts p
INNER JOIN wp_postmeta m ON p.ID = m.post_id
WHERE m.meta_key = 'specialite'
  AND m.meta_value = 'cardiologie'
  AND p.post_status = 'publish';

-- type: ALL, rows: 412 000, Extra: Using where

Plus de 400 000 lignes de wp_postmeta parcourues à chaque recherche, pour une table qui accumule plusieurs métadonnées par fiche (spécialité, service, dernière révision, auteur validant). L’index par défaut sur meta_key existait bien, mais MySQL ne l’exploitait pas efficacement dès lors que la sélectivité de la valeur associée entrait en jeu sur un tel volume.

La solution : un index composite ciblé

Plutôt que de remplacer le moteur de recherche, la correction a consisté à créer un index composite sur les colonnes réellement utilisées ensemble dans la clause WHERE, directement sur la table wp_postmeta :

ALTER TABLE wp_postmeta
ADD INDEX idx_specialite_lookup (meta_key(20), meta_value(50));
L'essentiel à retenir : Un plugin de recherche ne corrige jamais un schéma de base mal indexé ; Un index composite cible exactement les colonnes utilisées ensemble ; EXPLAIN révèle immédiatement un scan de table complet

Ce type d’index composite permet à MySQL d’évaluer les deux conditions (clé et valeur de métadonnée) en une seule traversée d’index, sans avoir à charger les lignes correspondantes en mémoire pour les filtrer ensuite une par une. Après création de cet index, la même requête EXPLAIN affichait type: ref avec seulement 340 lignes parcourues, contre 412 000 auparavant.

Résultat mesuré en production

Après déploiement de l’index en heures creuses (une opération ALTER TABLE sur une table de cette taille verrouille l’écriture pendant sa construction, ce qui impose de la planifier hors des heures de forte affluence), le temps de réponse de la recherche par spécialité est passé de huit secondes à 90 millisecondes en moyenne, mesuré sur cinquante recherches successives couvrant différentes spécialités.

Pourquoi un plugin de recherche tiers n’aurait rien résolu

Un plugin de recherche basé sur Elasticsearch ou un moteur externe aurait effectivement contourné le problème, en déportant la recherche hors de MySQL. Mais cette solution aurait ajouté une dépendance infrastructurelle supplémentaire (un service à maintenir, une synchronisation d’index à surveiller) pour corriger un problème qui tenait, in fine, à l’absence d’un index de quelques kilo-octets sur une table existante. Sur un intranet hospitalier où chaque composant supplémentaire doit être validé par les équipes techniques de l’établissement, la solution la plus simple était aussi la plus rapide à déployer.

  • Toujours isoler la requête SQL réelle avant de blâmer le plugin de recherche.
  • Passer systématiquement par EXPLAIN pour vérifier le type d’accès utilisé (ALL est le signal d’alerte).
  • Planifier les ALTER TABLE sur de grosses tables en dehors des heures de forte activité.

Avant de changer d’outil, vérifiez toujours si le problème ne tient pas simplement à un index manquant sur la table qui reçoit la requête.

En résumé

Sur ce projet, la lenteur perçue de la recherche interne d’un intranet de 100 000 pages ne venait ni du thème, ni du moteur de recherche WordPress, mais d’un schéma de base dépourvu d’index composite adapté au volume réel de métadonnées. Un ALTER TABLE ciblé, précédé d’un diagnostic rigoureux via EXPLAIN, a suffi à diviser le temps de réponse par près de cent, sans ajouter la moindre dépendance externe au projet.

Partager :

À propos de l'auteur

Clément Hadrot

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

Voir tous ses articles

Dans la même veine

À lire aussi