vendredi 25 septembre 2026

À propos

Contact

Performance

Un audit de performance qui a divisé par deux les requêtes d’un intranet

Étude de cas d'un intranet d'entreprise à 300 utilisateurs simultanés dont les requêtes SQL par page ont été divisées par deux après un audit ciblé sur les extensions internes.

Par Clément Hadrot • 19 décembre 2025 • 5 min de lecture • Aucun commentaire
Un audit de performance qui a divisé par deux les requêtes d'un intranet

L’intranet d’un groupe industriel de taille moyenne, construit sur WordPress avec une dizaine d’extensions internes développées au fil des années par différentes équipes successives, servait environ 300 utilisateurs simultanés aux heures de pointe (9 h et 14 h), avec des temps de chargement jugés « acceptables mais pas confortables » par les équipes RH qui en étaient les commanditaires. Un audit de performance a été commandé non pas suite à un incident, mais en prévention, avant une extension prévue du nombre d’utilisateurs suite à une fusion.

Un profil de charge différent d’un site public

Ce qui distingue un intranet d’un site public en matière de performance : la quasi-totalité des visiteurs sont authentifiés, ce qui exclut d’office tout cache de page HTML classique pour la plupart des écrans, chacun affichant un contenu personnalisé (annuaire, demandes de congés, actualités filtrées par service). La charge se concentre donc presque entièrement sur PHP et la base de données, sans le filet de sécurité qu’apporte un cache de page pour un site public.

La méthode d’audit

L’audit a démarré par une instrumentation de Query Monitor sur un panel de dix écrans représentatifs de l’usage réel (tableau de bord d’accueil, annuaire, demande de congés, actualités de service), avec une compilation manuelle du nombre de requêtes SQL par écran et de leur origine (cœur WordPress, extension tierce, extension interne).

L'essentiel à retenir : Un intranet expose des profils de charge différents d'un site public ; Les extensions internes maison concentraient l'essentiel des requêtes redondantes ; Un plugin de mise en cache de requêtes a suffi, sans changer l'architecture
ÉcranRequêtes SQL (avant audit)Origine principale
Tableau de bord d’accueil68Extension interne « widgets RH »
Annuaire41Extension interne « annuaire LDAP »
Demande de congés52Extension interne « workflow congés »
Actualités de service29Cœur WordPress (WP_Query standard)

La moyenne, toutes pages confondues, s’établissait à 47 requêtes par chargement, un chiffre qui aurait pu sembler correct isolément mais qui, multiplié par les 300 utilisateurs simultanés en pointe, représentait une charge de base de données significative sur un serveur MySQL par ailleurs peu dimensionné pour ce volume.

Ce que l’audit a trouvé dans les extensions internes

Les trois extensions internes concentraient à elles seules plus de 70 % des requêtes observées, pour des raisons similaires d’un module à l’autre : chaque widget du tableau de bord d’accueil exécutait sa propre requête indépendante pour vérifier les permissions de l’utilisateur connecté, sans partager ce résultat entre widgets pourtant affichés sur la même page. Le widget « congés en cours de l’équipe » interrogeait la table des utilisateurs une fois par membre de l’équipe affiché, dans une boucle, plutôt qu’en une seule requête groupée.

// Avant : une requête par membre de l'équipe, dans une boucle
foreach ( $membres_equipe as $id_membre ) {
    $conges = $wpdb->get_results( $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}conges WHERE id_utilisateur = %d AND statut = 'valide'",
        $id_membre
    ) );
    // ...
}
// Après : une seule requête groupée avec IN()
$ids = implode( ',', array_map( 'absint', $membres_equipe ) );
$conges = $wpdb->get_results(
    "SELECT * FROM {$wpdb->prefix}conges WHERE id_utilisateur IN ($ids) AND statut = 'valide'"
);
$conges_par_membre = [];
foreach ( $conges as $c ) {
    $conges_par_membre[ $c->id_utilisateur ][] = $c;
}

Un correctif transversal : mise en cache des vérifications de permissions

Au-delà des corrections ponctuelles dans chaque extension, l’audit a identifié un motif récurrent : la vérification des permissions d’un utilisateur (à quel service appartient-il, quels droits a-t-il) était recalculée à chaque widget, alors qu’elle ne change jamais au cours d’une même requête de page. Une fonction utilitaire, partagée entre les trois extensions internes, met désormais ce résultat en cache le temps d’une requête via un cache statique en mémoire.

function obtenir_permissions_utilisateur_courant() {
    static $cache = [];
    $id_utilisateur = get_current_user_id();

    if ( isset( $cache[ $id_utilisateur ] ) ) {
        return $cache[ $id_utilisateur ];
    }

    $cache[ $id_utilisateur ] = calculer_permissions_depuis_ldap( $id_utilisateur );
    return $cache[ $id_utilisateur ];
}

Résultat mesuré

La moyenne de requêtes SQL par chargement de page est passée de 47 à 23, soit une division quasiment par deux, sans qu’aucune modification d’architecture serveur n’ait été nécessaire : ni changement de version de MySQL, ni ajout de cache d’objet Redis, ni montée en puissance matérielle. Le temps de chargement moyen du tableau de bord d’accueil, mesuré aux heures de pointe, est passé de 1,8 à 0,9 seconde.

  • Un intranet concentre sa charge sur PHP et la base, sans filet de cache de page.
  • Les extensions internes maison, moins revues qu’une extension publique populaire, méritent un audit régulier.
  • Regrouper des requêtes répétées en boucle est souvent le correctif le plus rentable pour l’effort investi.

Une extension interne n’a jamais eu à convaincre personne de sa qualité pour être adoptée ; c’est précisément pour cette raison qu’elle mérite l’audit le plus attentif.

Hors périmètre

Cet audit ne traite pas la sécurité de l’intranet (contrôle d’accès, exposition réseau), sujet suivi séparément par l’équipe de sécurité informatique du groupe et hors du périmètre de cette mission centrée sur la performance.

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