Table des matières :
- Cadre reproductible : versions, périmètre et risques (sinon vos chiffres ne valent rien)
- Mesures cibles : TTFB, Core Web Vitals, p95… et séparation « synthétique » vs « terrain »
- Instrumentation “server-first” : prouver où part le temps (webserver → PHP-FPM → MySQL)
- Preuves côté base : slow queries, EXPLAIN, index… et pièges spécifiques PrestaShop
- PHP/PrestaShop : profilage, hooks, overrides, caches… et ce que le cœur ne fait pas pour vous
- Front-end et preuves UX : LCP/INP, JS inutile, images… et validation “terrain”
Cadre reproductible : versions, périmètre et risques (sinon vos chiffres ne valent rien)
Un audit performance PrestaShop reproductible commence par figer le contexte. À minima : version exacte de PrestaShop (ex. 8.1.x / 8.2.x / 9.1.x), version PHP (8.2/8.3), SAPI (PHP-FPM vs mod_php), moteur SQL (MySQL 8 vs MariaDB 10/11), serveur web (Nginx/Apache/LiteSpeed), et présence d’un CDN/WAF. Sans ça, comparer “avant/après” relève de la divination : une mise à jour mineure de PHP ou un changement de MPM Apache peut déplacer vos p95 de plusieurs dizaines de millisecondes sans que votre code n’ait bougé.
Pour éviter l’angle mort “on a changé 3 choses en même temps”, documentez aussi les paramètres qui influencent directement la latence, pas seulement les versions :
| Composant | Paramètre à noter | Pourquoi ça change vos chiffres |
|---|---|---|
| PHP-FPM | pm (dynamic/ondemand), pm.max_children, request_terminate_timeout |
saturation/queue, timeouts “cachés” |
| OPcache | mémoire, validate_timestamps |
cache misses, invalidations trop fréquentes |
| MySQL | buffer pool, tmp_table_size, max_connections |
tables temporaires disque, contention |
| Reverse proxy/CDN | cache HIT/MISS, cookies qui bypass | TTFB “magiquement bon” ou au contraire impossible à cache |
La seconde condition, c’est la parité des données et de la charge. Les audits faits sur une base “jouet” de 500 produits ne révèlent pas les vrais goulets : recherche, facettes, paniers, règles de prix, pages catégorie à 50k produits, tables ps_specific_price, ps_product_attribute, etc. Si vous auditez sur staging, il faut une copie anonymisée de la prod (au moins structure + cardinalités), et un scénario de navigation réaliste (pages produit, catégorie, panier, checkout).
Mini-scenario utile (et très fréquent) : une boutique B2C a “seulement” 8 000 produits, mais des déclinaisons nombreuses + des règles de prix empilées. La volumétrie “catalogue” paraît raisonnable, pourtant les tables liées (attributes, specific prices, combinaisons) changent complètement la complexité SQL côté listing et panier. Si votre audit ne reproduit pas cette densité de données, vous optimisez un site qui n’existe pas.
Pour éviter de confondre performance applicative et instabilité, vous devez aussi tracer les erreurs : un 503 intermittent “améliore” artificiellement des métriques côté navigateur (requête annulée) tout en détruisant l’expérience. Sur ce point, gardez une procédure de diagnostic serveur à portée, cf. Erreur HTTP 503 : diagnostiquer PHP et logs Apache/LiteSpeed.
Enfin, annoncez clairement les risques : activer un general_log MySQL en production peut tuer le disque et donc la boutique ; activer un profiler PHP en continu augmente la latence ; purger le cache en prod pendant un pic marketing est un sabotage. Un audit sérieux isole les changements (feature flags, maintenance window), documente les reversibility steps (rollback, restore), et garde des sauvegardes exploitables.
Checklist “anti-accident” avant de toucher la prod :
- Fenêtre : définir une période d’observation (ex. 2–4 h) + une période de changement (ex. 15 min) + une période de stabilisation.
- Plan de retour arrière : snapshot/backup + procédure testée (pas juste “on a une sauvegarde”).
- Journalisation contrôlée : activer logs/profilers avec seuils et durée (et une personne responsable de la désactivation).
- Communication : notifier marketing/support si vous risquez de dégrader le checkout.
Si vous êtes déjà sur une trajectoire CI/CD, le cadre “déploiements automatisés + environnements jetables” rend l’audit beaucoup plus propre (et testable), cf. PrestaShop : modernisation et reprise de boutique avec déploiements automatisés.
Mesures cibles : TTFB, Core Web Vitals, p95… et séparation « synthétique » vs « terrain »
Si vous dites “le site est lent” sans métriques, vous n’avez rien. Un audit performance PrestaShop doit produire au minimum : TTFB (server response), LCP/INP/CLS (UX), taille des réponses, nombre de requêtes SQL, et latences p50/p95/p99 côté serveur. Google fixe des seuils UX clairs ; par exemple web.dev rappelle : « To provide a good user experience, sites should strive to have Largest Contentful Paint of 2.5 seconds or less » (source : web.dev). Notez que LCP/INP sont des métriques client, fortement corrélées au thème, au JS, au réseau et au device. Les confondre avec un problème backend est l’erreur la plus courante.
Une règle simple pour garder un audit “honnête” : mesurer en percentiles (p75/p95), pas en moyenne. Une moyenne “jolie” peut cacher un site qui s’effondre dès qu’il y a du trafic, des bots, ou un pic de concurrence CPU.
Séparez donc deux axes :
- Mesure synthétique (reproductible) : Lighthouse CI, WebPageTest,
curl -wpour le TTFB, load tests (k6/wrk). Avantage : contrôlable, comparable dans le temps. - Mesure terrain (RUM) : données réelles via Performance API,
Server-Timing, ou agrégateurs (si vous en avez). Avantage : reflète les vrais devices et vrais réseaux.
Côté reproductibilité, imposez des budgets et des scénarios. Exemple minimal (à adapter) :
- Page catégorie : TTFB p95 < 400 ms, SQL queries < 120, payload HTML < 200 KB gzip.
- Page produit : LCP p75 < 2.5 s sur mobile “mid-tier”, INP p75 < 200 ms.
- Checkout : p95 backend < 600 ms sur les étapes critiques.
Pour cadrer vos mesures, une matrice simple évite d’oublier l’essentiel :
| Type de page | Mesure backend | Mesure frontend | Pourquoi c’est critique |
|---|---|---|---|
| Catégorie | TTFB p95 + requêtes SQL | LCP (image/hero) + JS listing | page SEO + entrée catalogue |
| Produit | temps hooks/modules + cache | LCP image produit + INP | conversion + expérience |
| Panier/Checkout | p95 + erreurs 5xx | INP (clics, champs) | chiffre d’affaires direct |
Pour cadrer “TTFB et back”, plusieurs articles du site posent déjà les bases (hébergement, caches, latence), notamment PrestaShop lent : diagnostic TTFB, bots et optimisation serveur et Hébergement PrestaShop Suisse : performance TTFB, cache Redis, PHP 8.x.
Enfin, ajoutez une dimension géographique sans surinterprétation : si votre clientèle est majoritairement en Suisse (ou en zone frontalière), vos tests synthétiques doivent être lancés depuis une localisation proche (et pas uniquement “Paris” par habitude), sinon vous mélangez latence réseau et latence serveur. Même principe si votre boutique cible plusieurs pays : vous aurez plusieurs vérités terrain.
Instrumentation “server-first” : prouver où part le temps (webserver → PHP-FPM → MySQL)
Commencez par prouver si le problème est réseau, webserver, PHP-FPM, ou SQL. Un TTFB de 1.2 s peut être : saturation PHP-FPM (queue), DNS lent, TLS handshake, disque saturé, locks SQL, ou modules PrestaShop qui déclenchent 300 requêtes. Sans instrumentation, vous allez “optimiser” au hasard. La méthode USE (Utilization, Saturation, Errors) est un bon garde-fou ; Brendan Gregg la résume ainsi : « For every resource, check utilization, saturation, and errors » (source : https://www.brendangregg.com/usemethod.html).
Sur un stack Nginx + PHP-FPM, activez au minimum :
pm.status_pathPHP-FPM (pour voirlisten queue,max children reached).- logs d’accès avec timings :
$request_time,$upstream_response_time. Server-Timingpour exposer côté navigateur une ventilation (ex.app;dur=120,sql;dur=80).
Deux mesures “low cost” qui donnent rapidement une direction :
- TTFB brut par URL (hors navigateur) pour comparer des endpoints à cookies constants :
curl -s -o /dev/null -w "ttfb=%{time_starttransfer} total=%{time_total}\n" https://exemple.com/categorie
- Corrélation logs ↔ charge : si
rtmonte en même temps quelisten queue, vous êtes côté PHP-FPM (pas côté MySQL, pas côté front).
Exemple Nginx (à adapter) :
log_format timed '$remote_addr - $request $status '
'rt=$request_time urt=$upstream_response_time '
'uaddr=$upstream_addr';
access_log /var/log/nginx/access_timed.log timed;
Pour un audit “terrain”, la supervision en continu évite les biais (un test de 5 minutes hors pic ne vaut rien). Si vous avez déjà Netdata, vous pouvez corréler CPU steal, iowait, connexions SQL, queue PHP-FPM, etc. Voir Netdata : intégrer Prometheus, SNMP et StatsD pour tout surveiller pour industrialiser la collecte.
Point de méthode (souvent oublié) : gardez les mêmes conditions applicatives entre runs. Exemple concret : si un run a un cache chaud (Redis/Varnish) et l’autre un cache froid (purge involontaire, redéploiement), vous comparez des états différents. Notez systématiquement : HIT/MISS, cookies présents, utilisateur connecté vs non.
Preuves côté base : slow queries, EXPLAIN, index… et pièges spécifiques PrestaShop
Dans PrestaShop, la base est souvent le premier “multiplicateur” de latence : des requêtes modestes deviennent catastrophiques avec la volumétrie, les jointures sur tables de déclinaisons, ou les règles de prix. Activez et exploitez le slow query log de façon contrôlée (fenêtre courte, seuil raisonnable). Le manual MySQL définit le principe sans ambiguïté : « The slow query log consists of SQL statements that took more than longquerytime seconds to execute » (source : dev.mysql.com). L’objectif : sortir une liste courte de requêtes pires que p95, pas de logger la planète.
Procédure d’audit “safe” (sans noyer la prod) :
- Choisir une fenêtre (ex. 10–20 minutes en trafic représentatif).
- Fixer
long_query_timede façon pragmatique (ex. 0.2–0.5 s pour commencer, selon votre TTFB cible). - Extraire top 10 (par temps cumulé + fréquence), plutôt que “la plus lente” isolée.
- Corréler avec les URLs (quand c’est possible via
performance_schema, logs applicatifs, ou patterns).
Une fois la requête lente identifiée, passez immédiatement à EXPLAIN / EXPLAIN ANALYZE (MySQL 8) et vérifiez : type d’accès (ALL vs ref), cardinalités estimées, filesort, temporary tables. Beaucoup de boutiques traînent des index manquants ou invalides après des migrations, désinstallations de modules, ou imports massifs. Ce sujet est suffisamment récurrent pour être traité comme une checklist : Index MySQL : composer, mesurer avec EXPLAIN et optimiser les requêtes.
Pièges terrain typiques :
ps_search_index/ps_facetedsearch: explosion des jointures, tables temporaires, et caches invalidés trop souvent. Pour des catalogues lourds, une externalisation de recherche (Elasticsearch/OpenSearch/Meilisearch) est parfois plus rationnelle que “tuner MySQL à l’infini”, cf. Elasticsearch PrestaShop : accélérer la recherche et les facettes catalogue.- tables de logs applicatifs, stats, paniers abandonnés : croissance non maîtrisée → scans longs → buffer pool pollué. Ici, le “gain performance” vient souvent d’une politique de rétention (archivage/purge) plus que d’un index miracle.
- contention (locks) : imports/exports et cron agressifs qui écrasent la prod. Si vous êtes sur Lightsail ou similaire, assurez-vous d’avoir les logs nécessaires pour prouver la contention, cf. Logs Amazon Lightsail : activer general log et slow query MySQL.
Astuce très opérationnelle en audit : distinguez requête lente (mauvais plan, index, filesort) et requête bloquée (lock). Les deux “font du temps”, mais ne se traitent pas pareil. Si vos lenteurs apparaissent uniquement pendant un import, une synchronisation stock, ou un cron de module, l’action prioritaire est souvent de déplacer/limiter la tâche plutôt que d’optimiser le SELECT.
PHP/PrestaShop : profilage, hooks, overrides, caches… et ce que le cœur ne fait pas pour vous
Quand la DB n’explique pas tout, vous devez profiler le code. PrestaShop reste un hybride legacy + Symfony : énormément de logique passe par des hooks, des services, des appels indirects, et des objets reconstruits à la volée. La méthode reproductible : profiler sur un scénario (page catégorie, produit, panier) avec un outil (Blackfire, XHProf, Tideways) et produire des flamegraphs. Le but n’est pas de “gagner 2 ms” mais d’identifier les fonctions dominantes (ex. parsing de règles de prix, construction de facettes, surcharge de Product::getProducts). Pour une approche structurée de profilage PHP/Symfony, cf. Optimisation code source : audit performance PHP/Symfony avec profilage.
Un livrable d’audit utile côté PHP n’est pas “on a profilé” : c’est une liste priorisée du type :
- Top 5 hotspots (fonction/méthode) + coût (ms cumulé, appels).
- Origine (core, thème, module X, override Y).
- Action (cache, refactor, suppression, déport asynchrone) + risque (régression, compatibilité).
Sur le runtime PHP, OPcache n’est pas optionnel. La doc PHP le résume simplement : « OPcache improves PHP performance by storing precompiled script bytecode in shared memory » (source : php.net). En audit, vous vérifiez : opcache.enable=1, memory suffisante, opcache.validate_timestamps cohérent avec votre stratégie de déploiement, et surtout les symptômes de saturation (restarts FPM, cache misses, invalidations trop fréquentes).
Côté PHP-FPM, évitez le piège “on monte pm.max_children et ça ira mieux”. Si chaque worker consomme beaucoup (plugins, gros contexte), vous pouvez juste déplacer le problème vers l’OOM et les swaps. La démarche propre :
- mesurer la RAM typique d’un worker sous charge (profiling +
ps/Netdata), - fixer
pm.max_childrenen fonction de la RAM réellement disponible, - puis vérifier si la queue (
listen queue) disparaît aux heures de pointe.
Ensuite seulement vous discutez Redis, Varnish, CDN, etc. Une stratégie cache 2026 (OPcache + Redis + reverse proxy + CDN) est détaillée ici : Cache PrestaShop : stratégie 2026 OPcache, Redis, Varnish et CDN.
Côté architecture PrestaShop, deux points font mal en prod :
1) Modules et hooks : chaque module peut ajouter du SQL, du rendering Smarty, ou des appels HTTP. Sans discipline, une page produit déclenche 40 hooks * x modules = latence exponentielle. Faites une matrice : hook → module → coût (ms, requêtes SQL, payload). Astuce très pragmatique : cherchez d’abord les modules qui ajoutent des appels externes (tracking, avis, recommandations) — ils sont souvent “faibles en CPU” mais très forts en latence et variabilité.
Et si vous développez, évitez les overrides “par défaut” : ils masquent les coûts et compliquent les mises à jour. Pour cadrer une livraison propre sans override, cf. Module PrestaShop sans override : méthode de cadrage, tests et livraison du code.
2) Caches applicatifs : le cœur de PrestaShop ne vous “sauvera” pas si votre thème ou vos modules invalident le cache à chaque requête (ou si vous servez des pages non cacheables à cause de cookies inutiles). Revoyez la gestion des cookies, des headers Cache-Control, et la séparation HTML vs fragments dynamiques. Les erreurs classiques en multiboutique (contextes, caches croisés) sont listées dans Cache PrestaShop : erreurs fréquentes et bonnes pratiques multiboutique.
Front-end et preuves UX : LCP/INP, JS inutile, images… et validation “terrain”
Une boutique peut avoir un backend correct et rester lente “côté utilisateur” à cause du front. En 2026, les métriques qui comptent côté navigation sont dominées par : taille et priorité des images (LCP), JS bloquant (INP), et CSS non critique (render-blocking). L’audit performance PrestaShop doit donc inclure une passe DevTools : waterfall, coverage JS/CSS, points de blocage, et identification du vrai LCP element (souvent l’image produit ou un hero).
Une séquence d’audit front-end qui marche bien (et se prouve) :
- Identifier l’élément LCP réel (DevTools / WebPageTest).
- Vérifier sa priorité réseau : est-il demandé tôt ? est-il sur CDN ? est-il bloqué par du CSS/JS ?
- Mesurer le JS “inutile” (Coverage) et repérer les bundles chargés sur toutes les pages alors qu’ils ne servent qu’au checkout.
- Relever les scripts tiers (tag manager, widgets) et leur coût en “long tasks” (INP).
L’efficacité vient d’actions simples et mesurables : convertir en WebP/AVIF (si compatible), fetchpriority="high" sur l’image LCP, preload strictement ciblé, et suppression de JS “décoratif”. Sur les optimisations de base (images, cache, MySQL), vous avez déjà un socle ici : PrestaShop performance : optimiser cache, images WebP et base MySQL.
Côté thème, un point est devenu très concret : la dépendance historique à jQuery et à des handlers obsolètes. Les évolutions Chrome autour de unload ont forcé des migrations et exposent les scripts hérités qui se déclenchent trop tard ou bloquent les transitions. Si votre thème/module manipule la navigation, lisez et testez : Événement unload Chrome : guide de migration et Permissions-Policy. Ce n’est pas “juste un détail navigateur” : c’est un indicateur que vous avez des patterns de code front vieillissants, souvent associés à de mauvais INP.
La validation “terrain” doit boucler la boucle :
- Ajoutez
Server-Timinget comparez avec les traces backend (profiling, slow queries) pour prouver la causalité. - Lancez un test synthétique stable (ex. WebPageTest sur 5 runs, médiane) et une fenêtre RUM (ex. 7 jours) pour vérifier que l’amélioration ne concerne pas uniquement votre laptop fibre.
- Fixez un garde-fou anti-régression : Lighthouse CI en pipeline, et seuils p95 backend sur les endpoints critiques.
Exemple de résultats terrain (pattern réel, chiffres typiques)
Sur une boutique PrestaShop 8.2.x / PHP 8.2 / MySQL 8, cas fréquent : pages catégorie à forte volumétrie avec ps_facetedsearch, et un thème lourd. Après instrumentation (Nginx timings + slow log + profiling), les preuves montraient : (1) p95 TTFB à ~900 ms avec 65% du temps côté SQL, (2) requête dominante avec filesort + table temporaire, (3) JS front avec 40–60% de code non utilisé sur listing.
Plan d’action validé par mesures : ajout d’index ciblés (sur colonnes de filtrage les plus actives), réduction de jointures inutiles via configuration facettes, et refonte du chargement JS (code splitting + suppression plugins). Résultat typique observé : p95 TTFB abaissé de ~900 ms à ~420–500 ms sur listing, LCP p75 mobile amélioré d’environ 0.6–1.2 s (selon réseau) une fois l’image/hero priorisé et le JS bloquant réduit.
Une façon simple de rendre ces gains “présentables” (et comparables dans 3 mois) est de consigner un tableau avant/après par endpoint critique :
| Page | Indicateur | Avant | Après | Preuve |
|---|---|---|---|---|
| Catégorie | TTFB p95 | ~900 ms | ~420–500 ms | logs Nginx + slow log |
| Catégorie | % temps SQL | ~65% | en baisse (selon requête) | EXPLAIN ANALYZE |
| Listing | LCP p75 mobile | variable | -0.6 à -1.2 s | RUM + WebPageTest |
Le point clé : chaque amélioration était reliée à une preuve (trace SQL, flamegraph, waterfall), pas à une “impression”.
Pour industrialiser, verrouillez la méthode : un runbook versionné (Git), une base de comparaison (mêmes URLs, mêmes cookies, même device profile), et des tests de charge légers (k6) après chaque lot. C’est aussi ce qui rend l’audit exploitable par une équipe (dev, ops, SEO) plutôt que dépendant d’un individu.




