PrestaShop performance : optimiser cache, images WebP et base MySQL

Stratégies concrètes pour accélérer PrestaShop : mesurer TTFB, activer OPcache, servir WebP, optimiser MySQL et déployer avec purge/warmup sans casser le cache.

Ordinateurs avec code pour l'optimisation des performances de PrestaShop.

Table des matières :

  1. Mesurer la performance PrestaShop avant de toucher au cache, aux images ou à MySQL
  2. Optimiser le cache : du cache opcode au full-page cache sans casser les sessions
  3. Images WebP dans PrestaShop : génération, serving et impact Core Web Vitals
  4. Base MySQL/MariaDB : optimiser InnoDB, requêtes lentes et tables typiques PrestaShop
  5. Nettoyage de base, contention et limites du cœur PrestaShop (qu’il faut assumer)
  6. Mise en production : purge, warmup, CI/CD et rollback (sinon vos optimisations ne tiennent pas)
  7. Checklist “PrestaShop performance” (ordre de ROI) : cache, WebP, MySQL

Mesurer la performance PrestaShop avant de toucher au cache, aux images ou à MySQL

Optimiser “à l’aveugle” sur PrestaShop finit presque toujours en régression : cache trop agressif qui sert des paniers à la mauvaise personne, génération d’images qui sature le CPU, ou tuning MySQL qui masque juste un N+1 côté PHP. Le point de départ minimal, en 2026, c’est de séparer trois latences : TTFB (serveur), temps de rendu (front), temps DB (SQL). Sur une boutique PrestaShop 8.1/8.2 ou 9.x (Symfony 6.4), avec PHP 8.2/8.3, la majorité des lenteurs “ressenties” côté utilisateur vient d’une somme : TTFB élevé + images trop lourdes + JS/CSS non critique.

Pour éviter les diagnostics “ça dépend”, fixez un cadre simple : une page = un scénario = un jeu de mesures, et distinguez toujours cache froid vs cache chaud. Exemple : une page catégorie peut être très rapide après warmup (cache applicatif rempli), mais catastrophique après un purge (cache miss + requêtes facettes + compilation Twig).

Repères pratiques (à adapter à votre secteur, thème, modules et trafic) :

Indicateur Ce que ça représente Cible “saine” (ordre de grandeur) Comment le mesurer vite
TTFB latence serveur (PHP + DB + réseau) < 400–800 ms sur pages publiques curl -w / RUM / APM
LCP affichage de l’élément principal < 2,5 s “bon”, 2,5–4 s “à améliorer” Lighthouse / données terrain
CLS stabilité visuelle < 0,1 Lighthouse / Web Vitals
INP réactivité interactions < 200 ms Web Vitals / RUM

Astuce “anti-biais” : mesurez depuis une zone proche de votre audience (par ex. France/Benelux/Europe si c’est votre marché) et depuis un point plus lointain. Une boutique peut être “OK” depuis un serveur de test à Paris, mais lente en conditions mobiles réelles si le poids image et le JS dominent.

Côté outils, gardez un pipeline simple et reproductible : (1) curl -w pour isoler le TTFB, (2) Chrome DevTools / Lighthouse pour LCP/CLS, (3) APM (New Relic/Datadog) ou au minimum slow_query_log MySQL et un profilage PHP ponctuel.

Deux compléments qui évitent des heures de fausses pistes :

  • Vérifier les en-têtes (cache, cookies, compression) sur les pages testées : un Set-Cookie sur une page censée être cacheable est souvent un “tueur de CDN/Varnish”.
  • Mesurer avec et sans “bruit” : bots, outils SEO, scans de sécurité. Une hausse du TTFB peut venir d’un trafic non-humain qui déclenche des pages coûteuses (facettes, recherche, variantes).

Enfin, validez votre “baseline” sur des parcours e-commerce réalistes : page catégorie (tri + pagination), page produit, ajout panier, panier, checkout (au moins l’étape adresse/livraison). Si votre boutique utilise fortement ps_facetedsearch, la page catégorie est souvent le point chaud n°1. Pour cadrer le diagnostic TTFB, vous pouvez vous appuyer sur l’article interne PrestaShop lent : diagnostic TTFB, bots et optimisation serveur

Optimiser le cache : du cache opcode au full-page cache sans casser les sessions

Sur PrestaShop, “activer le cache” dans le BO ne règle pas le problème de fond : le cœur alterne legacy et Symfony, et beaucoup de contrôleurs front restent très dynamiques (prix, stock, promos, personnalisation, panier). Il faut raisonner en couches : OPcache (bytecode PHP), cache applicatif (Symfony/PrestaShop), cache de données (Redis/Memcached), cache HTTP (Varnish/CDN). Une stratégie structurée est détaillée dans Cache PrestaShop : stratégie 2026 OPcache, Redis, Varnish et CDN

Commencez par OPcache, parce que c’est le ROI le plus stable et le moins “piégeux” fonctionnellement. En PHP-FPM, l’objectif est d’éviter les invalidations permanentes et les sur-allocations. En prod, opcache.validate_timestamps=0 + déploiement atomique (symlink) est généralement plus sain qu’un validate_timestamps=1 qui recompile au fil des requêtes. Exemple (PHP 8.2/8.3) :

; php.ini (production)
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=60000
opcache.validate_timestamps=0
opcache.jit=0

Points de contrôle simples après activation :

  • opcache_get_status() (ou l’équivalent via une page d’admin / outil) : taux de hit, mémoire consommée, fichiers “cached”.
  • Surveiller les erreurs 502/504 après déploiement : elles peuvent venir d’un redémarrage PHP-FPM non coordonné, pas du cache en lui-même.

Ensuite seulement, posez Redis comme cache de données (sessions, cache Symfony, éventuellement Doctrine si vous avez des modules qui l’utilisent). Le piège classique en e-commerce est le cache “global” qui oublie de varier par groupe client/devise/pays. Dans PrestaShop, la personnalisation n’est pas seulement “mon compte” : les prix peuvent varier (groupes, taxes, devises), et certaines pages publiques peuvent déjà inclure des éléments dépendants d’un cookie (ex. contenu du mini-panier, recommandations module).

Si vous ajoutez un cache HTTP (Varnish/CDN), appliquez une règle stricte : ne jamais mettre en cache les routes sensibles (/panier, /commande, /mon-compte, endpoints Ajax qui dépendent du panier) et varier correctement quand c’est nécessaire (cookies, en-têtes Accept-Language, etc.). Un test rapide et très concret consiste à :

  • appeler deux fois la même URL en anonyme,
  • vérifier si le cache répond (Age, X-Cache, CF-Cache-Status selon infra),
  • puis refaire le test après création d’un panier : si la page publique “non critique” change, vous avez une dépendance cookie à traiter (exclusion ou variation).

Mini-scénario (classique) : une boutique B2B active un full-page cache “généreux” sur les pages catégories. Les clients “connectés” voient des prix spécifiques. Si la variation par cookie/groupe n’est pas correctement gérée, un visiteur anonyme peut recevoir une version mise en cache avec des prix B2B, ou inversement. La performance “augmente”, mais la boutique devient incohérente commercialement.

Si vous cherchez un cadrage CDN côté infra, l’article interne CDN : comparatif Cloudflare, Fastly, Akamai, CloudFront, Bunny.net, KeyCDN est un bon point d’entrée.

Images WebP dans PrestaShop : génération, serving et impact Core Web Vitals

Le “poids image” est le facteur le plus prévisible à optimiser sur un catalogue : vous contrôlez le format, la compression et la stratégie de chargement. Google résume le format sans ambiguïté : « WebP is a modern image format that provides superior lossless and lossy compression for images on the web. » (web.dev / Google) web.dev/serve-images-webp. Sur des boutiques PrestaShop, l’impact est directement visible sur LCP (Largest Contentful Paint), car l’élément LCP est très souvent l’image produit ou la bannière hero.

Côté métriques, Google a aussi publié une étude chiffrée souvent citée : « WebP images are 25-34% smaller than comparable JPEG images » (Google Developers, WebP Study) developers.google.com/speed/webp/docs/webp_study. En pratique, le gain dépend de votre source (JPEG déjà optimisé ou non), mais une baisse de 20–40% sur les images principales est réaliste. Si votre LCP est “borderline” (2,5–4s sur mobile), c’est un levier nettement plus fiable que de micro-optimiser un template.

Avant de “basculer en WebP”, vérifiez deux points qui font souvent perdre du temps :

  • Quel est vraiment l’élément LCP ? Sur certains thèmes, le LCP n’est pas l’image produit mais un bloc texte/slider, ce qui déplace le problème vers CSS/JS (chargement bloquant, polices, carrousel).
  • Quelle image est réellement servie sur mobile ? Sans srcset/sizes cohérents, un smartphone peut télécharger une image “desktop” (trop grande), ce qui annule le gain du WebP.

Le cœur de PrestaShop (8.x/9.x) ne délivre pas nativement du WebP “automatique” pour toutes les images, et la régénération d’images peut être coûteuse. Deux approches fiables en prod :

1) Générer WebP à la génération d’images (cron/queue) et servir conditionnellement.
2) Conversion à la volée au niveau CDN (si votre CDN le supporte) pour éviter de toucher au disque local.

En pratique, la génération “hors ligne” est souvent plus prévisible en ressources : vous planifiez une régénération la nuit, vous savez combien de fichiers sont produits, et vous évitez que les premiers visiteurs “paient” la conversion.

Si vous gérez vous-même Nginx, le serving conditionnel WebP se fait proprement via Accept + Vary: Accept. Exemple simplifié (attention : à adapter à votre arborescence img/p/... et à votre naming) :

map $http_accept $webp_suffix {
  default "";
  "~*webp" ".webp";
}

location ~* ^/img/p/(.+)\.(jpe?g|png)$ {
  add_header Vary Accept;
  try_files $uri$webp_suffix $uri =404;
  expires 30d;
  add_header Cache-Control "public, max-age=2592000, immutable";
}

Le point critique : ne cassez pas les URLs existantes (SEO + caches externes) et ne multipliez pas les variantes inutiles. Si vous utilisez des srcset/sizes (recommandé), assurez-vous que vos tailles PrestaShop correspondent à de vrais breakpoints front (sinon vous générez des fichiers qui ne seront jamais demandés).

Checklist “images” (rapide, mais efficace) :

  • L’image LCP est-elle préchargée (ou au moins priorisée) et non lazy-load ? (lazy-load sur l’image LCP est un anti-pattern fréquent).
  • Les bannières “hero” sont-elles traitées comme des images produit (compression, dimensions, format), ou exportées “brutes” depuis un outil graphique ?
  • Les miniatures (listing catégorie) sont-elles calibrées pour éviter le surdimensionnement (ex. 600px livrés pour un affichage 180px) ?

Pour l’audit “front”, l’article interne Thème PrestaShop : passer à Hummingbird sans jQuery, focus accessibilité donne une bonne grille de lecture sur la dette JS/CSS qui pénalise aussi LCP.

Base MySQL/MariaDB : optimiser InnoDB, requêtes lentes et tables typiques PrestaShop

Si le TTFB est haut malgré OPcache et un cache applicatif correct, la base est souvent le goulet. PrestaShop génère beaucoup de requêtes courtes, parfois redondantes (surtout via modules), et certaines pages déclenchent des agrégations lourdes (facettes, prix spécifiques, stock avancé). Le minimum syndical : activer le slow query log, capturer des exemples réels sur 24–48h (incluant bots), puis classer par temps total (latence × fréquence). Pour une méthode d’audit reproductible, voir l’article interne Audit MySQL/MariaDB : optimiser les requêtes lentes e‑commerce

Un point souvent sous-estimé : dans un contexte e-commerce, une requête “pas si lente” (ex. 80–150 ms) peut devenir un problème si elle est appelée des dizaines de fois par page (N+1), ou si elle s’exécute sur un pic de concurrence (checkouts simultanés). D’où l’intérêt de trier les requêtes par coût cumulé, pas uniquement par temps max.

Sur InnoDB, la mémoire est la variable la plus déterminante : si votre buffer pool est sous-dimensionné, vous payez en I/O disque et en latence. La doc MySQL est explicite : « The buffer pool is the memory area where InnoDB caches table and index data. » (MySQL Reference Manual) dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html. En e-commerce, viser 60–75% de la RAM (serveur dédié) pour innodb_buffer_pool_size est un ordre de grandeur courant, à ajuster selon cohabitation (Redis, PHP-FPM, Elasticsearch/OpenSearch, etc.). Sur un VPS “serré”, mieux vaut un buffer pool plus petit mais stable qu’un OOM killer qui tue MySQL.

Pour prioriser sans se tromper, commencez par savoir quelles tables grossissent et quelles tables sont les plus lues. Un extrait simple (à adapter à votre préfixe) pour repérer les tables les plus volumineuses :

SELECT
  table_name,
  ROUND((data_length + index_length) / 1024 / 1024, 1) AS size_mb,
  ROUND(index_length / 1024 / 1024, 1) AS index_mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY (data_length + index_length) DESC
LIMIT 15;

Dans PrestaShop, les suspects “typiques” varient selon votre configuration, mais on retrouve souvent :

  • tables liées au catalogue et aux déclinaisons (volume + jointures),
  • tables de prix spécifiques (conditions, dates, groupes),
  • tables de logs/statistiques (croissance continue),
  • tables “cache” de modules (qui gonflent si non purgées).

L’optimisation “SQL pure” dans PrestaShop passe souvent par :

  • indexer correctement les colonnes de jointure utilisées par les modules (beaucoup oublient des indexes),
  • réduire les SELECT * et les requêtes répétées par produit (N+1),
  • maîtriser la cardinalité sur les tables de logs/statistiques.

Un exemple concret : si une page catégorie avec facettes déclenche des WHERE id_category = ? AND id_shop = ? AND id_lang = ? sur de grosses tables, un index composite cohérent peut faire passer un plan de table scan à un index range scan. Avant de créer des indexes “à l’instinct”, utilisez EXPLAIN ANALYZE (MySQL 8) / EXPLAIN (MariaDB) et vérifiez le gain réel. Attention aussi au “faux bon plan” : un index ajouté peut accélérer la lecture… mais ralentir l’écriture (mise à jour stock, import catalogue), donc l’évaluation doit couvrir vos tâches batch (imports, synchro ERP/PIM).

Pour les effets de bord côté ps_facetedsearch (URLs combinées, explosion de combinaisons), l’article interne Recherche à facettes PrestaShop : configurer ps_facetedsearch et filtres combinés complète bien la démarche.

Nettoyage de base, contention et limites du cœur PrestaShop (qu’il faut assumer)

Le cœur PrestaShop accumule facilement de la donnée “inutile en prod” : paniers abandonnés, connexions, stats, tables temporaires de modules, index fulltext laissés à l’abandon, etc. Le résultat n’est pas seulement un stockage qui gonfle : ce sont des tables plus volumineuses, des indexes moins efficaces, et des sauvegardes plus lentes (donc des fenêtres de maintenance plus risquées). Le nettoyage n’est pas glamour, mais c’est souvent ce qui débloque des latences bizarres, surtout quand la base dépasse quelques dizaines de Go.

Deux règles simples pour une hygiène qui ne casse pas le métier :

  • Ne pas confondre “donnée inutile” et “donnée sensible/utile” : on purge rarement les commandes, clients, factures (obligations comptables), mais on peut souvent traiter des logs techniques et du bruit (connexions/pages vues) avec une politique de rétention.
  • Automatiser et journaliser : un nettoyage “à la main” tous les 6 mois finit par être oublié. Un job planifié + un log (nombre de lignes supprimées, durée, impact) rend l’opération robuste.

Sur ce point, un article interne est directement actionnable : Optimisation PrestaShop : nettoyer la base et configurer le cache natif. Même si vous ne gardez pas les mêmes choix de cache, la partie “hygiène DB” reste valide : purger proprement, archiver si nécessaire, et surtout mesurer (taille table/index, fragmentation, fréquence d’écriture). Si vous êtes sur MariaDB, gardez aussi un œil sur les évolutions récentes côté optimiseur/InnoDB (article interne MariaDB 11.4) : MariaDB 11.4 – nouveautés, correctifs InnoDB et optimiseur

La contention est l’autre problème silencieux : en pic de trafic, ce n’est pas “une requête lente” mais “beaucoup de requêtes qui se bloquent”. Sur PrestaShop, ça arrive sur certaines écritures : panier, stock, ps_cart, tables de sessions selon implémentation, et parfois des tables de modules. Sur MySQL/MariaDB, surveillez Threads_running, InnoDB_row_lock_time, Handler_read%, et les waits (Performance Schema / SHOW ENGINE INNODB STATUS). Si vous n’avez pas d’observabilité continue, mettez-en une : l’article interne Netdata : intégrer Prometheus, SNMP et StatsD pour tout surveiller aide à bâtir une vue exploitable.

Un signal très “terrain” de contention : tout semble correct en journée, puis à une heure de pic (campagne e-mail, pub, soldes), le checkout “plante” alors que le CPU n’est pas saturé. Dans ce cas, cherchez du côté des locks DB et des écritures synchrones (sessions, panier, stock), plutôt que d’augmenter uniquement les ressources PHP.

Mise en production : purge, warmup, CI/CD et rollback (sinon vos optimisations ne tiennent pas)

Optimiser la performance PrestaShop n’est pas juste “changer 3 réglages” : c’est une discipline de déploiement. Exemple typique : vous activez opcache.validate_timestamps=0, vous déployez par SFTP en écrasant des fichiers, et vous vous retrouvez avec un mix de code ancien/nouveau en mémoire. Pour éviter ça, adoptez un déploiement atomique (répertoire versionné + symlink), puis redémarrage contrôlé de PHP-FPM et purge ciblée des caches applicatifs.

Un déroulé “propre” (simple, mais robuste) ressemble souvent à :

  1. Déployer la nouvelle release dans un nouveau répertoire (sans toucher à la prod active).
  2. Basculer le symlink (switch atomique).
  3. Redémarrer/reload PHP-FPM (pour OPcache) au bon moment.
  4. Purger le cache applicatif (Symfony/PrestaShop) si nécessaire.
  5. Purger CDN/Varnish de façon ciblée (pas un “flush all” si vous pouvez l’éviter).
  6. Warmup des pages clés.
  7. Contrôle post-déploiement : TTFB, erreurs 5xx, logs, métriques DB.

Pour le cache HTTP (Varnish/CDN), la purge doit être ciblée (par URL, tag, ou surrogate keys) et idéalement déclenchée par vos workflows (mise à jour produit/catégorie). Si vous partez sur un hébergement géré qui gère staging et maintenance, vous déléguez une partie de l’opérationnel, mais vous restez responsable des règles de cache et des exclusions e-commerce. Voir : Hébergement PrestaShop géré : migration sans coupure, staging et maintenance. Si vous êtes plutôt côté infra “maison”, l’article Serveur dédié PrestaShop : config Nginx PHP-FPM MariaDB Redis est un socle concret.

Le warmup est souvent négligé : après purge, vous subissez un “cold start” (cache miss) au pire moment, et vous créez un cache stampede. Implémentez un warmup minimal (pages catégories clés + 1–2 best-sellers) via un job CI/CD ou un cron post-déploiement, en veillant à ne pas polluer le cache avec des sessions connectées.

À ajuster : si vous utilisez un cache HTTP, vous ne voudrez pas forcément forcer l’origine ; l’idée est surtout d’éviter le warmup “avec cookies” et de déclencher la génération des pages et des fragments critiques de façon contrôlée.

Pour industrialiser proprement les tests de compatibilité (PHP/versions), vous pouvez aussi vous inspirer de ChaosLab : tester modules PrestaShop sur 23 environnements PHP

Checklist “PrestaShop performance” (ordre de ROI) : cache, WebP, MySQL

Premier palier (souvent < 1 jour, risque faible) : mesure + OPcache + headers de cache statiques (assets themes/, modules/, img/ hors images produits dynamiques). Stabilisez PHP-FPM (pm settings, limites mémoire), puis traitez les régressions évidentes (images hero trop lourdes, JS bloquant). Si vous êtes sur PrestaShop 9.x, gardez en tête le socle Symfony/PHP : l’article interne PrestaShop 9 : guide de migration Symfony 6.4 et PHP 8.3 permet de sécuriser la compatibilité runtime avant d’optimiser finement.

Deuxième palier (1 à 3 jours, risque moyen) : WebP (ou conversion CDN) + Redis pour réduire la latence applicative et absorber le trafic. C’est aussi le bon moment pour durcir les exclusions de cache (panier/checkout) et vérifier que vous ne servez jamais du contenu personnalisé en cache partagé. Si vous avez déjà une stratégie SEO (canonical, hreflang), gardez la cohérence lors de changements d’URLs d’images et de templates : Référencement PrestaShop : optimiser fiches produits, catégories, canonical et hreflang

Troisième palier (variable, risque élevé si mal exécuté) : audit MySQL/MariaDB, indexes ciblés, réglages InnoDB, purge/archivage, et éventuellement refactor de modules qui génèrent des requêtes inutiles. Sur les boutiques à fort trafic, ce travail finit souvent par une décision d’architecture (scaling vertical vs lecture répliquée vs séparation services). Si vous hésitez entre rester “100% relationnel” ou introduire d’autres moteurs pour des cas spécifiques, l’article interne MySQL vs MongoDB : critères techniques pour projets à fort trafic peut cadrer les critères sans dogme.

Enfin, gardez une règle d’or : chaque optimisation doit avoir une mesure “avant/après” sur un scénario identique (même page, mêmes paramètres, même contexte cache). C’est le moyen le plus sûr d’améliorer durablement les Core Web Vitals sans dégrader le fonctionnel (prix, panier, stock) — et donc sans “gagner 300 ms” en en perdant 3 jours en support.


À lire aussi