Voici une frustration que nous entendons sans cesse : votre boutique PrestaShop était rapide au lancement, puis un an plus tard les mêmes pages se traînent. Même hébergement, même thème, mêmes modules, rien de visible n’a changé. Alors que s’est-il passé ? Dans une grande partie de ces cas, le responsable est précisément l’élément qui, lui, a changé en silence, chaque jour d’ouverture : votre base de données. Par défaut, PrestaShop journalise une quantité impressionnante d’activité, et les tables qui contenaient quelques centaines de lignes au lancement en comptent désormais des millions. Des requêtes instantanées sur une petite table deviennent un frein mesurable sur une table énorme ; et comme vos pages produit, pages catégorie et votre back-office consultent toutes ces tables, le ralentissement se diffuse partout à la fois.

Ce guide traite précisément du gonflement de base de données qui s’accumule avec le temps : quelles tables grossissent, pourquoi elles grossissent, ce que vous pouvez nettoyer sans risque, et comment le faire sans casser votre boutique. Ce n’est pas un article généraliste sur "pourquoi PrestaShop est lent" (les modules, l’hébergement et le poids du front-end sont d’autres causes, nous les abordons dans ce qui ralentit vraiment PrestaShop), et il ne s’agit pas non plus de contourner des requêtes lentes avec du cache (Redis et le cache pleine page ont leurs propres articles). Ici, nous parlons de ce qui s’accumule à l’intérieur même des tables.

Les tables qui gonflent et la politique de nettoyage sûre ci-dessous restent valables pour PrestaShop 1.7, 8.x et 9.x. Les tables de statistiques présentes varient selon la version et les modules installés : lancez donc toujours la requête d’audit en premier, et mesurez votre propre schéma avant de cibler quoi que ce soit.

Pourquoi les bases PrestaShop grossissent en silence

PrestaShop embarque un système de statistiques et de journalisation qui enregistre bien plus de choses que la plupart des marchands ne l’imaginent. Connexions, sessions invité, recherches internes, 404, journaux d’e-mails envoyés, paniers abandonnés : lorsque les fonctionnalités de statistiques et de logs correspondantes sont activées, tout finit dans la base de données, et la rétention reste presque entièrement à votre charge. PrestaShop n’applique pas de politique intégrée du type "garder 90 jours", et la purge dépend des modules et de la configuration en place. Résultat : dans la plupart des boutiques, les données s’accumulent tout simplement.

Pour une boutique modeste à 500 visiteurs par jour, le calcul est implacable :

  • ps_connections, une ligne par connexion visiteur. 500/jour, cela fait environ 15 000/mois, 182 000/an, et cela ne s’arrête jamais.
  • ps_connections_source, suivi des référents/HTTP referers pour chaque connexion ; cette table est souvent plus volumineuse que ps_connections elle-même.
  • ps_guest, une ligne par invité unique (empreinte navigateur/OS/écran), accumulée pour chaque visiteur non connecté.
  • ps_log, le journal applicatif. Un seul module trop bavard qui génère des notices peut écrire plusieurs lignes par chargement de page et faire grimper cette table à plusieurs millions de lignes.
  • ps_pagenotfound, chaque 404, y compris le trafic incessant des bots qui sondent /wp-admin, /phpmyadmin et autres chemins du même genre.
  • ps_statssearch, chaque requête de recherche interne saisie par un visiteur.
  • ps_cart et ps_cart_product, chaque panier jamais créé, dont l’immense majorité n’a jamais abouti à une commande.
  • ps_mail, un journal de chaque e-mail envoyé par PrestaShop.
  • les tables de statistiques natives (ps_statssearch, ps_searchengine et, sur certaines installations, ps_referrer/ps_referrer_cache), la couche analytique que presque personne ne consulte réellement dans PrestaShop, parce que la plupart utilisent Google Analytics à la place. Les tables exactes présentes dépendent de votre version de PrestaShop, des modules statistiques installés et de l’historique des mises à jour de la base : auditez donc le schéma réel avant d’en cibler une, au lieu de supposer une liste fixe.

La conséquence est simple : après deux ou trois ans, ces tables contiennent couramment des millions de lignes, le jeu de données actif de MySQL ne tient plus confortablement en mémoire, le buffer pool InnoDB sature, et même les requêtes bien indexées ralentissent parce que le moteur lit davantage de pages sur disque. Votre boutique n’est pas devenue plus lourde d’une façon visible pour le visiteur : elle s’est alourdie là où seule la base de données le ressent.

Commencez par identifier ce qui est réellement gonflé dans votre boutique

SELECT table_name, table_rows, ROUND((data_length + index_length) / 1024 / 1024, 1) AS mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
  AND table_name LIKE 'ps\_%'
ORDER BY (data_length + index_length) DESC
LIMIT 20;

Ne nettoyez pas à l’aveugle. Chaque boutique gonfle différemment selon son trafic et les modules installés ; la première étape consiste donc à mesurer la taille des tables. Exécutez ceci dans phpMyAdmin (ou Adminer, ou le CLI MySQL), en remplaçant le nom de votre vraie base de données : la requête liste vos plus grosses tables par nombre de lignes et par taille sur disque :

  • SELECT table_name, table_rows, ROUND((data_length + index_length)/1024/1024, 1) AS size_mb FROM information_schema.tables WHERE table_schema = 'your_db_name' ORDER BY (data_length + index_length) DESC LIMIT 25;

Lisez le résultat avant de toucher à quoi que ce soit. Si vos plus grosses tables sont ps_orders, ps_order_detail et ps_product_lang, c’est un gonflement sain : de vraies données métier que vous devez conserver. Si le haut de la liste affiche ps_connections, ps_guest, ps_log, ps_statssearch ou ps_pagenotfound, vous avez trouvé des données inutiles qui peuvent peser plusieurs gigaoctets. Cette seule requête vous indique si le reste de l’article vous concerne, et quelles tables cibler.

Quelles tables nettoyer, et lesquelles ne jamais toucher

C’est ici que les guides deviennent dangereux : il faut être précis. Les tables se répartissent en trois groupes.

TableCe qu’elle contientPolitique de nettoyage
ps_connectionsJournal des connexions visiteursDELETE filtré par date pour garder 30 à 90 jours, ou TRUNCATE si vous ne conservez rien. GA fait mieux ce travail.
ps_connections_sourceRéférents par connexionÀ nettoyer avec ps_connections.
ps_guestEmpreintes des visiteurs invitésÀ nettoyer avec ps_connections (attention à la FK vers ps_customer).
ps_logJournal applicatif/erreursLire d’abord les erreurs récentes, puis tronquer.
ps_pagenotfoundJournal des 404Survoler pour repérer de vrais liens cassés, puis tronquer.
ps_statssearchRequêtes de recherche interneGarder environ 90 jours pour les insights merchandising, DELETE filtré par date pour les lignes plus anciennes.
ps_mailJournal des e-mails envoyésGarder les entrées récentes pour le support, tronquer l’ancien.
ps_cart / ps_cart_productPaniers, abandonnés comprisSupprimer uniquement les paniers orphelins (sans commande) de plus de 30 à 60 jours.
ps_customer_session / ps_employee_sessionLignes de jetons de session (1.7.6.6+)Les lignes expirées peuvent partir ; préserver les sessions actives. Elles sont minuscules, ce n’est pas une vraie source de gonflement.
ps_orders + ps_order_*Données de commandeNe jamais supprimer, conservation légale (souvent 7 à 10 ans).
ps_customerComptes clientsSupprimer uniquement sur demande RGPD, jamais en masse.
ps_product + relatedCatalogueJamais. Les produits désactivés restent liés aux commandes.
ps_configurationRéglages de la boutiqueJamais. Une mauvaise ligne peut casser la boutique.

La table des paniers demande un scalpel, pas un marteau

L’erreur que nous voyons le plus souvent consiste à tronquer entièrement ps_cart pour récupérer de l’espace. Ne le faites pas. Une ligne de panier sans id_cart correspondant dans ps_orders est un panier abandonné et peut être supprimée une fois assez ancienne ; un panier qui est lié à une commande fait partie de l’historique de cette commande. Le schéma sûr identifie uniquement les paniers orphelins plus anciens qu’une fenêtre donnée, puis supprime d’abord leurs lignes enfants dans ps_cart_product, et ensuite les paniers eux-mêmes, afin de ne pas laisser de références orphelines. La méthode fiable consiste à construire d’abord une liste de valeurs id_cart candidates, puis à supprimer selon cette liste. Ce qui permet aussi un nettoyage propre par lots. Notez que MySQL n’autorise pas LIMIT sur un DELETE multi-table (JOIN) ; nous évitons donc entièrement la forme JOIN dans la suppression elle-même :

  • CREATE TEMPORARY TABLE tmp_orphan_carts AS SELECT c.id_cart FROM ps_cart c LEFT JOIN ps_orders o ON o.id_cart = c.id_cart WHERE o.id_order IS NULL AND c.date_add < DATE_SUB(NOW(), INTERVAL 60 DAY);
  • DELETE FROM ps_cart_product WHERE id_cart IN (SELECT id_cart FROM tmp_orphan_carts) LIMIT 20000;, répétez jusqu’à ce que 0 ligne soit affectée.
  • DELETE FROM ps_cart WHERE id_cart IN (SELECT id_cart FROM tmp_orphan_carts) LIMIT 20000;, là encore, répétez jusqu’à 0 ligne.
  • DROP TEMPORARY TABLE tmp_orphan_carts;

Chaque DELETE cible maintenant une seule table sans jointure : le LIMIT 20000 est donc valide, et vous pouvez relancer chaque instruction jusqu’à ce qu’elle ne supprime plus rien. Terminez toujours les suppressions enfants dans ps_cart_product avant de supprimer les lignes parentes dans ps_cart. Ce traitement par lots est volontaire : la section suivante explique pourquoi il compte plus qu’il n’y paraît.

Comment nettoyer sans risque et sans mettre la boutique à genoux

Étape 1, sauvegarder la base, sans exception

Avant tout DELETE ou TRUNCATE, effectuez une sauvegarde complète des données (mysqldump ou snapshot de votre hébergeur). L’outil natif de PrestaShop Paramètres avancés → Base de données → Sauvegarde BDD existe, mais pour de grosses tables, un mysqldump côté serveur est plus fiable. Si un nettoyage tourne mal, la restauration est votre seul filet de sécurité : considérez-la comme obligatoire, pas optionnelle.

Étape 2, supprimer par lots, pas avec une requête géante

DELETE FROM ps_connections
WHERE date_add < DATE_SUB(NOW(), INTERVAL 180 DAY)
LIMIT 5000;

Un seul DELETE qui supprime deux millions de lignes pose un verrou long et peut rendre votre boutique inaccessible pendant son exécution. Travaillez par lots de 10 000 à 50 000 lignes (le LIMIT dans les requêtes de panier ci-dessus), avec une courte pause entre les passages, et répétez jusqu’à ce que la table soit propre. Lorsque vous voulez une fenêtre de rétention plutôt qu’une table vide, garder les 90 derniers jours, supprimer le reste, utilisez un DELETE filtré par date comme DELETE FROM ps_connections WHERE date_add < DATE_SUB(NOW(), INTERVAL 90 DAY) LIMIT 50000;, répété jusqu’à ce qu’il indique 0 ligne. Ce n’est que lorsque vous voulez vraiment supprimer tout le contenu d’une table de logs jetable qu’il faut utiliser TRUNCATE TABLE ps_connections; : c’est beaucoup plus rapide, car la table est supprimée puis recréée au lieu de retirer les lignes une à une, mais il n’est pas filtrable par date et réinitialise l’auto-incrément. Réservez-le donc au vidage complet de tables, et faites-le dans un ordre sûr si des tables liées se référencent entre elles.

Étape 3, récupérer l’espace disque avec OPTIMIZE TABLE

Voici la partie que les marchands oublient. PrestaShop utilise InnoDB, et après un gros DELETE, le nombre de lignes baisse mais le fichier sur disque ne rétrécit pas : l’espace libéré reste réservé sous forme de fragmentation interne, et les requêtes peuvent encore lire ces pages vides. Vous devez reconstruire explicitement la table :

  • OPTIMIZE TABLE ps_connections, ps_connections_source, ps_guest, ps_log, ps_pagenotfound, ps_statssearch;

Avec InnoDB, OPTIMIZE TABLE reconstruit la table et réanalyse ses index, ce qui défragmente les données. Le retour effectif d’espace au système d’exploitation dépend de votre configuration : avec innodb_file_per_table activé, le réglage par défaut sur les MySQL/MariaDB modernes, chaque table possède son propre tablespace et l’espace libéré est rendu au système de fichiers ; sur un tablespace système partagé, ce n’est pas le cas. La reconstruction peut aussi verrouiller ou copier la table selon votre version et configuration MySQL/MariaDB. Lancez-la donc après les suppressions, dans une fenêtre de maintenance ou de faible trafic, et vérifiez le comportement sur votre version serveur précise avant de compter sur la récupération d’espace.

Étape 4, vider le cache PrestaShop uniquement si nécessaire

Supprimer des lignes dans des tables de logs et de statistiques est un nettoyage de données, pas un changement de code ou de schéma ; cela ne nécessite donc normalement pas de vider le cache. PrestaShop ne met pas en cache ces lignes de logs brutes. Videz le cache uniquement si le nettoyage a touché des données actuellement mises en cache quelque part (par exemple des statistiques de tableau de bord alimentant un widget en cache), ou après des changements de code, de module ou de schéma qui invalident réellement la sortie compilée. Quand c’est nécessaire, utilisez Paramètres avancés → Performances → Vider le cache dans le back-office (ou supprimez le contenu de var/cache/) ; sur les versions qui maintiennent un index de classes compilé, sa reconstruction fait partie de la même opération.

Le faire depuis le back-office plutôt qu’en SQL brut

Liste d'état de nettoyage de l'intégrité système avec des vérifications telles que version de PHP, état des modules, tables de base de données, fragmentation des tables, lignes nettoyables et taille du cache, chacune marquée comme pas encore vérifiée, au-dessus des boutons Configuration auto et Lancer la vérification d'intégrité

La liste d’état vérifie la version de PHP, les modules, les tables de la base de données, la fragmentation, les lignes nettoyables et la taille du cache, chacun marqué comme pas encore vérifié.

Écran de configuration de Database Cleanup

La configuration doit vivre dans le module, pas dans du SQL improvisé conservé sur l’ordinateur de quelqu’un.

Le SQL brut est précis mais impitoyable : un JOIN manquant et vous orphelinisez une commande. Si vous préférez ne pas écrire de DELETE contre une boutique en production, vous avez deux options plus sûres directement dans PrestaShop :

  • SQL Manager (intégré) : Paramètres avancés → Base de données → Gestionnaire SQL vous permet d’enregistrer et de relancer la requête d’audit de taille ci-dessus ainsi que tous les contrôles en lecture seule. C’est d’abord un outil SELECT, mais c’est l’endroit approprié pour mesurer avant et après, et pour garder votre requête d’audit à portée de main mois après mois.
  • Un module de maintenance : un module de nettoyage dédié gère la logique des paniers orphelins, les suppressions par lots et l’étape OPTIMIZE depuis un écran de back-office avec cases à cocher, sans SQL, et avec les opérations destructrices protégées par une confirmation. C’est la voie que nous recommanderions à un marchand non développeur, précisément parce qu’elle supprime le risque de se tromper de touche sur un DELETE visant ps_orders.

Quel que soit votre choix, la politique reste la même que dans le SQL ci-dessus : seul l’outil change la sûreté de l’exécution.

Rendez-le récurrent, pas annuel et paniqué

Le gonflement est continu, le nettoyage doit donc l’être aussi. Une boutique nettoyée une fois puis oubliée retrouve les mêmes volumes de lignes en quelques mois. Mettez en place une routine mensuelle fixe :

  • Parcourir rapidement ps_log et ps_pagenotfound pour repérer ce qui est réel (erreurs récurrentes, véritables liens cassés), puis tronquer les entrées de plus de 30 jours.
  • Supprimer les paniers orphelins de plus de 60 jours (les deux requêtes panier ci-dessus), d’abord les enfants dans ps_cart_product, puis les paniers.
  • Supprimer les lignes ps_connections, ps_connections_source et ps_guest de plus de 90 jours avec un DELETE filtré par date (attention à la FK ps_guest → ps_customer), ou les tronquer directement si vous n’appliquez aucune fenêtre de rétention.
  • Réduire ps_statssearch et ps_mail à environ 90 jours avec le même schéma de DELETE filtré par date.
  • Lancer OPTIMIZE TABLE sur tout ce que vous avez nettoyé.

Toute la séquence peut vivre dans un script SQL lancé chaque mois par un cron job sur votre serveur, ou être exécutée selon un planning par un module de maintenance. L’automatisation fait la différence entre une boutique qui reste rapide et une boutique qui revient discrètement à des pages chargées en 4 secondes pendant que vous êtes occupé à gérer l’activité.

Un niveau plus bas : les index et les requêtes elles-mêmes

Élaguer les lignes est le geste le plus rentable, parce qu’il réduit d’un coup chaque parcours de table ; mais deux sujets liés méritent d’être mentionnés pour bien poser la limite :

  • Index manquants dans des modules tiers. Beaucoup de modules créent leurs propres tables sans indexer les colonnes utilisées pour filtrer. Activez le slow query log de MySQL, surveillez les requêtes qui scannent entièrement une table de module, puis ajoutez un index sur la colonne WHERE/JOIN. Une table propre avec le bon index peut transformer une requête de 2 secondes en quelques millisecondes.
  • Réglage MySQL au niveau serveur (innodb_buffer_pool_size et consorts) et optimisation plus large des requêtes relèvent d’une autre discipline : c’est le domaine de l’hébergement et de la configuration, traité dans l’optimisation des performances, des requêtes de base de données au cache pleine page et le choix d’un hébergement pour PrestaShop. Nettoyer les données d’abord signifie que vous optimisez une base légère plutôt qu’une base envahie ; faites donc cette étape avant d’acheter un plus gros serveur.

Mesurez l’avant et l’après, correctement

Ne vous fiez pas à une impression de "ça semble plus rapide". Avant de nettoyer, relevez votre TTFB (Time to First Byte) sur un ensemble constant de pages : page d’accueil, une page produit, une page catégorie et le tableau de bord du back-office (l’administration est souvent l’endroit où le gonflement fait le plus mal, car les tables de statistiques alimentent ces widgets). Notez aussi les tailles de vos plus grosses tables à partir de la requête d’audit. Après le nettoyage et OPTIMIZE, mesurez à nouveau les mêmes pages et les mêmes tables.

Nous ne vous donnerons pas de pourcentage garanti : le gain dépend entièrement du niveau de gonflement initial. Une boutique dont ps_connections contient trois ans de logs verra une amélioration bien plus nette qu’une boutique déjà propre. Si vos diagnostics ne pointent pas clairement vers la base de données, commencez par une vérification structurée de lenteur plutôt que de deviner : votre boutique est-elle lente, comment vérifier et quoi faire. Et si vous voulez voir à quoi ressemble un PrestaShop entièrement optimisé de bout en bout, nous en avons documenté un ici : PageSpeed 99/100 sur une vraie boutique avec 130 modules.

Le principe reste valable quelle que soit la méthode choisie : PrestaShop peut parfaitement se journaliser jusqu’à l’asphyxie si vous le laissez faire, parce que rien ne purge ces tables à votre place. Identifiez votre gonflement réel, supprimez uniquement ce qui est vraiment jetable, récupérez l’espace avec OPTIMIZE, puis mettez le tout sur un planning. Faites cela, et votre boutique conserve la vitesse qu’elle avait le jour du lancement, même après des années d’exploitation, sans rien acheter.

Questions fréquentes

Est-il sûr de tronquer ps_connections et ps_guest ?

Tronquer ps_connections et ses tables associées (ps_connections_source, ps_connections_page) est sûr si vous n’utilisez pas les statistiques natives de PrestaShop : ces tables alimentent une analytique que la plupart des marchands remplacent de toute façon par Google Analytics. ps_guest demande un peu plus de prudence à cause de son lien par clé étrangère vers ps_customer ; préférez un DELETE filtré par date qui garde les lignes récentes plutôt qu’un TRUNCATE aveugle. Ce que vous ne devez jamais tronquer, c’est ps_cart : les paniers abandonnés y sont mélangés à des paniers liés à de vraies commandes. Celui-ci demande le scalpel limité aux orphelins présenté plus haut, pas un marteau.

J’ai supprimé des millions de lignes, mais le disque n’a pas rétréci. Pourquoi ?

InnoDB ne rend pas l’espace libéré au système d’exploitation après un DELETE : le nombre de lignes baisse, mais le fichier sur disque garde la même taille, avec les pages libérées conservées comme fragmentation interne. Vous devez reconstruire la table avec OPTIMIZE TABLE pour le récupérer, et même alors, l’espace n’est rendu au système de fichiers que si innodb_file_per_table est activé (réglage par défaut sur les MySQL/MariaDB modernes). Lancez OPTIMIZE après les suppressions, dans une fenêtre de faible trafic, car l’opération peut verrouiller ou copier la table selon votre version.

Dois-je vider le cache PrestaShop après avoir nettoyé la base ?

En général, non. Supprimer des lignes dans des tables de logs et de statistiques est un nettoyage de données, pas un changement de code ou de schéma, et PrestaShop ne met pas ces lignes brutes en cache. Videz le cache uniquement si le nettoyage a touché des données actuellement mises en cache, par exemple des statistiques de tableau de bord alimentant un widget en cache, ou après de vrais changements de code, de module ou de schéma. L’élagage régulier des logs et des paniers ne l’exige pas.

Pourquoi supprimer par lots plutôt qu’en une seule requête ?

Un seul DELETE qui retire deux millions de lignes pose un verrou long et peut figer la boutique pendant son exécution. Travailler par lots de 10 000 à 50 000 lignes, avec une courte pause entre les lots, garde chaque verrou court et la boutique réactive. Utilisez un DELETE filtré par date avec un LIMIT, répété jusqu’à ce qu’il indique zéro ligne. TRUNCATE est l’exception : il est presque instantané parce qu’il supprime puis recrée la table, mais il ne peut pas être filtré par date. Réservez-le donc au vidage complet d’une table de logs jetable.

Est-ce que tout cela ne va pas simplement regonfler ?

Oui, c’est précisément l’intérêt de rendre l’opération récurrente. PrestaShop n’a pas de politique de rétention intégrée : une boutique nettoyée une seule fois retrouve les mêmes volumes de lignes en quelques mois. Placez la séquence (purger les tables de logs/statistiques/paniers, puis OPTIMIZE) dans un cron mensuel, ou laissez un module de maintenance l’exécuter selon un planning, afin que les tables n’aient jamais l’occasion de regrossir. L’automatisation fait la différence entre rester rapide et revenir discrètement à des chargements de page de 4 secondes.

Lectures associées

David Miller

David Miller

Fondateur, mypresta.rocks
À propos de l’auteur

David Miller est un spécialiste PrestaShop fort de plus de dix ans d'expérience concrète et le fondateur de mypresta.rocks, un studio de développement situé à Tychy, en Pologne. Il conçoit et maintient un catalogue de 159 modules PrestaShop, dont 21 suites « Revolution » couvrant le SEO, le checkout, la sécurité, la performance, le marketing, la recherche, le support et la gestion d'entrepôt, qui améliorent chaque jour de vraies boutiques, testés sur PrestaShop 1.7.8, 8.x et 9.x. Il assure également la maintenance de boutiques en production : son travail se juge donc sur des ventes réelles, pas sur des démos. Son expérience couvre l'ensemble du e-commerce. Performance, sécurité, SEO et marketing, et va au-delà de PrestaShop, jusqu'à WooCommerce, Shopify et les systèmes sur mesure. Sur le blog, il écrit sur la face technique de PrestaShop : ce que la plateforme fait vraiment, ce qui casse en production et quelles solutions tiennent dans la durée.

Partager cet article:

Commentaires

Aucun commentaire pour le moment. Soyez le premier !

Cet article vous a plu ?

Recevez nos derniers conseils, guides et mises à jour de modules dans votre boîte mail.

Vous pouvez vous désinscrire à tout moment. Vous trouverez pour cela nos informations de contact dans les conditions d'utilisation du site.

Chargement...
Retour en haut