Retour au blog
Performances & Benchmarks · 11 min de lecture

Checklist de tuning Postgres en production : les réglages qui réduisent vraiment la latence

Affane Daylami · Fondateur· 24 août 2026

Une checklist de tuning Postgres en production tient en cinq chantiers : connexions et pooling, mémoire, autovacuum, requêtes lentes et index, puis checkpoints et WAL. Le reste n'est qu'une variante de ces cinq points selon votre charge. Les paramètres qui reviennent le plus souvent, shared_buffers, work_mem et effective_cache_size, sont détaillés plus bas avec leurs repères de départ.

postgresql.conf par défaut n'est pas cassé, il est prudent : dimensionné pour tourner sur une machine minimale sans jamais faire échouer une installation, pas pour encaisser votre trafic de production. Passer de ces valeurs de compatibilité à des valeurs de production se mesure, ça ne se devine pas. Pour le protocole de mesure lui-même (charge réaliste, p50/p95/p99, résultats reproductibles), voir notre méthodologie de benchmark backend. Cet article-ci détaille les réglages eux-mêmes, dans l'ordre où ils comptent le plus.

L'essentiel
  • Cinq chantiers, dans l'ordre : connexions/pooling, mémoire, autovacuum, index/requêtes lentes, checkpoints/WAL.
  • max_connections et shared_buffers exigent un redémarrage complet du serveur ; la plupart des autres réglages se rechargent à chaud.
  • Ne jamais désactiver l'autovacuum en production : le vrai risque n'est pas la lenteur, c'est le wraparound d'ID de transaction.
  • pg_stat_statements doit être listé dans shared_preload_libraries avant qu'un simple CREATE EXTENSION ne collecte quoi que ce soit.
  • L'Advisor intégré à Aurabase Studio applique déjà une partie de cette checklist automatiquement : requêtes de plus de 150 ms, clés étrangères non indexées, pool de connexions au-delà de 80% de saturation.
#
Point de départ

Pourquoi les réglages par défaut de Postgres ne suffisent jamais

postgresql.conf, dans son état par défaut, est pensé pour ne jamais faire échouer une installation, pas pour absorber votre trafic. La valeur historique de shared_buffers, 128 Mo, permet à Postgres de démarrer sur une machine minimale sans réserver la moindre ressource critique. max_connections à 100 tient sur un petit serveur partagé. Aucune des deux n'a été choisie pour votre charge réelle.

Le problème n'est donc pas que Postgres soit mal réglé par défaut : c'est qu'il n'a jamais été réglé pour vous. Les sections qui suivent parcourent les réglages dans l'ordre où ils rapportent le plus, du plus fréquent goulot d'étranglement (les connexions) au plus lent à se manifester (le WAL).

#
Connexions

Dimensionner max_connections et le pooling avant tout le reste

Le premier chantier n'est pas la mémoire, ce sont les connexions. Chaque connexion Postgres ouvre un processus serveur dédié qui consomme de la RAM et du temps CPU de contexte, même inactif. Augmenter max_connections pour éviter des erreurs de type "too many connections" déplace le problème : au-delà d'un certain nombre de connexions actives simultanées, la contention CPU dégrade la latence de toutes les requêtes, y compris les plus rapides.

La bonne approche inverse l'ordre habituel : dimensionner max_connections sur la concurrence réelle du serveur, puis absorber la concurrence côté application avec un pooler comme PgBouncer en pool_mode=transaction. Le pooler multiplexe des centaines de connexions clientes sur une poignée de connexions serveur réellement actives. Notre article dédié détaille le mécanisme du mode transaction et ses limites (prepared statements, LISTEN/NOTIFY), et un comparatif oppose PgBouncer, Supavisor et PgCat pour choisir l'implémentation.

max_connections est un paramètre de contexte "postmaster" : le changer exige un redémarrage complet du serveur, pas un simple rechargement. Sur les instances Postgres dédiées d'Aurabase (plans Pro et Enterprise, un cluster CNPG par projet), ce paramètre est configuré par palier de plan plutôt que laissé à sa valeur par défaut. Un redémarrage n'est pas une opération anodine à répéter en production, ce qui justifie ce choix par palier plutôt qu'une valeur fixe. La formule pour choisir sa propre valeur, avec ses limites, fait l'objet d'un article séparé : dimensionner max_connections.

#
Mémoire

shared_buffers, work_mem, effective_cache_size : les réglages qui comptent

Quatre réglages mémoire pèsent plus que tous les autres réunis : shared_buffers, effective_cache_size, work_mem et maintenance_work_mem. Les trois premiers déterminent combien de données Postgres garde en mémoire avant de retourner sur disque ; le quatrième détermine la vitesse d'un VACUUM ou d'une création d'index.

shared_buffers fixe le cache interne partagé par toutes les connexions. Le repère communément documenté par le projet PostgreSQL est d'environ 25% de la RAM disponible sur un serveur dédié à la base. Au-delà, les gains diminuent et le cache disque du système d'exploitation prend le relais. effective_cache_size n'alloue rien : c'est une estimation, donnée au planificateur de requêtes, de la mémoire totale disponible pour le cache (Postgres et OS combinés). Le sous-dimensionner pousse le planificateur vers des scans séquentiels alors qu'un index tiendrait largement en cache ; le repère courant se situe entre 50 et 75% de la RAM.

work_mem est le piège le plus fréquent. Ce n'est pas une limite globale. Chaque opération de tri ou de hachage dans une requête peut en consommer sa propre part, et une requête avec plusieurs jointures peut en réserver plusieurs fois. Une valeur trop généreuse combinée à un max_connections élevé peut épuiser la RAM du serveur sous charge concurrente, même si chaque requête prise isolément paraît raisonnable. maintenance_work_mem, à l'inverse, peut rester nettement plus généreux : il ne s'applique qu'aux opérations de maintenance (VACUUM, CREATE INDEX), rarement concurrentes entre elles.

Seul shared_buffers exige un redémarrage. Les trois autres se rechargent à chaud, y compris pour une session isolée : SET work_mem = '64MB'; le temps d'une seule requête gourmande, sans toucher au réglage global.

#
Maintenance

Autovacuum : ajuster les seuils, ne jamais le désactiver

Ne désactivez jamais l'autovacuum en production, même temporairement pour "libérer des ressources" pendant un pic de charge. Postgres utilise le MVCC : chaque UPDATE et chaque DELETE laisse une ligne morte que seul le vacuum peut récupérer. Sans lui, les tables gonflent (bloat), les index se dégradent, et les plans d'exécution se détériorent progressivement, sans erreur visible avant qu'il ne soit tard.

Le vrai risque n'est pas la lenteur
Le danger le plus sérieux d'un autovacuum désactivé ou sous-dimensionné n'est pas la performance, c'est le wraparound d'ID de transaction. Passé un seuil, Postgres bascule la base entière en lecture seule pour éviter une corruption de données, jusqu'à ce qu'un VACUUM manuel s'exécute. C'est un incident de production entièrement évitable par une configuration correcte.

La valeur par défaut d'autovacuum_vacuum_scale_factor (20% de lignes mortes avant déclenchement) convient à une petite table, pas à une table de plusieurs millions de lignes à forte écriture. Sur une table de 10 millions de lignes, ces 20% représentent 2 millions de lignes mortes accumulées avant le premier passage. Abaissez ce seuil table par table plutôt que de changer la valeur globale de toute la base.

psql
SQL
-- Abaisser le seuil sur une table à forte écriture, pas globalement
ALTER TABLE orders SET (
autovacuum_vacuum_scale_factor = 0.05,
autovacuum_vacuum_cost_limit = 2000
);

L'Advisor intégré à Aurabase Studio vérifie cette configuration à chaque analyse de projet, au même titre que les tables sans clé primaire ou les clés étrangères non indexées. C'est un signal explicite plutôt qu'une dégradation silencieuse découverte trop tard.

#
Requêtes lentes

Indexer avant d'ajouter de la RAM

La majorité des problèmes de latence en production ne viennent ni du CPU ni de la RAM : ils viennent d'un index absent ou mal choisi. Avant de toucher à un seul paramètre de postgresql.conf, EXPLAIN (ANALYZE, BUFFERS) sur la requête en cause reste le diagnostic le plus fiable. Il réduit la latence des requêtes Postgres bien avant d'ajouter des ressources.

psql
SQL
-- Diagnostiquer une requête lente avant de toucher à la configuration
EXPLAIN (ANALYZE, BUFFERS)
SELECT o.id, o.total
FROM orders o
WHERE o.customer_id = '…'
ORDER BY o.created_at DESC
LIMIT 20;

Un Seq Scan sur une table de plusieurs millions de lignes, là où un Index Scan était attendu, signale presque toujours un problème d'index. Trois causes reviennent le plus souvent : un index absent, un type de colonne incompatible avec l'index existant, ou des statistiques obsolètes après un import massif sans ANALYZE. Ajouter de la RAM ou augmenter work_mem masque parfois ce symptôme sur un petit volume de données ; le problème réapparaît dès que la table grossit.

Pour repérer ces requêtes sans les chercher une par une, pg_stat_statements agrège les statistiques d'exécution de toutes les requêtes du serveur. Un piège fréquent : l'extension doit d'abord être listée dans shared_preload_libraries, un paramètre de contexte "postmaster" qui exige un redémarrage. Sans cette étape, CREATE EXTENSION pg_stat_statements; réussit silencieusement mais ne collecte rien.

postgresql.conf → psql
SQL
# Nécessite un redémarrage complet (paramètre "postmaster")
shared_preload_libraries = 'pg_stat_statements'
-- Une fois le serveur redémarré, dans chaque base à auditer :
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
SELECT query, calls, mean_exec_time, max_exec_time
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;

C'est exactement l'erreur que retourne le backend d'Aurabase quand cette extension est absente : un message explicite plutôt qu'une liste vide silencieuse, qu'on pourrait confondre avec "aucune requête lente". L'Advisor de Studio va plus loin : il classe automatiquement toute requête avec un temps moyen supérieur à 150 ms en avertissement, et au-delà de 500 ms en critique. Ces seuils s'appuient sur les mêmes statistiques pg_stat_statements.

#
Écriture disque

Checkpoints et WAL : lisser la charge plutôt que la subir

Un checkpoint force Postgres à écrire sur disque toutes les pages modifiées en mémoire depuis le précédent. Par défaut, cette écriture peut se concentrer sur une fenêtre de temps trop courte. Le résultat est un pic de latence disque perceptible côté application, le genre de ralentissement périodique difficile à relier à une requête précise.

checkpoint_completion_target contrôle l'étalement de cette écriture sur l'intervalle entre deux checkpoints. Un détail absent des checklists plus anciennes : PostgreSQL 14, sorti en 2021, a changé sa valeur par défaut de 0.5 à 0.9. Sur une instance en PostgreSQL 16, comme les clusters tenant dédiés d'Aurabase, ce réglage est donc déjà correct par défaut ; l'ajuster manuellement n'a de sens que sur une version antérieure à 14. Voir notre comparatif PostgreSQL 16 vs 17 vs 18 pour les autres changements de version qui affectent le tuning.

max_wal_size agit dans le même sens : une valeur trop basse déclenche des checkpoints plus fréquents qu'attendu, même quand checkpoint_timeout n'est pas encore atteint. L'augmenter réduit la fréquence des checkpoints, au prix d'un temps de récupération plus long après un crash puisqu'il y a plus de WAL à rejouer. Un compromis à trancher selon votre tolérance à l'indisponibilité, pas une valeur universelle.

#
Continu

Le monitoring n'est pas une étape, c'est la boucle qui referme la checklist

Cette checklist n'est pas un audit ponctuel à cocher une fois avant la mise en production. Une base qui double de volumétrie ou un trafic qui triple rendent obsolètes les repères choisis au démarrage, souvent sans erreur explicite, juste une dégradation progressive de la latence p95.

Trois signaux méritent une surveillance continue. pg_stat_statements repère les requêtes qui se dégradent dans le temps. pg_stat_activity signale les requêtes bloquées ou anormalement longues en cours d'exécution, et le ratio connexions actives sur max_connections anticipe une saturation avant qu'elle ne produise des erreurs côté application.

L'onglet Observabilité de Studio couvre une partie de ce socle pour tout projet Aurabase, sans outil tiers à installer. Il liste les requêtes lentes, permet d'annuler ou de terminer une requête active par PID, et affiche un indicateur de saturation du pool qui passe en avertissement au-delà de 80% d'utilisation. Sur une instance auto-hébergée, cette même surveillance se construit à la main, avec pg_stat_statements activé et un outil de supervision externe branché dessus.

#
Récapitulatif

Aide-mémoire : la checklist complète

Huit réglages, dans l'ordre où ils rapportent le plus, avec ce qu'il faut savoir avant d'y toucher.

max_connectionsRedémarrageDimensionné sur la concurrence réelle, pas un chiffre rond ; absorbez le reste via un pooler en mode transaction.
shared_buffersRedémarrage≈ 25% de la RAM dédiée à Postgres.
effective_cache_sizeÀ chaud≈ 50 à 75% de la RAM (Postgres + cache OS combinés).
work_memÀ chaud / sessionPrudent par défaut ; testez à la hausse requête par requête avec SET.
maintenance_work_memÀ chaudPlus généreux que work_mem ; accélère VACUUM et CREATE INDEX.
autovacuum_vacuum_scale_factorÀ chaud, par tableAbaissez sur les grandes tables à forte écriture, jamais globalement.
checkpoint_completion_targetÀ chaud0.9 par défaut depuis PostgreSQL 14 ; à vérifier surtout sur une version antérieure.
shared_preload_librariesRedémarrageDoit inclure pg_stat_statements avant toute analyse de requêtes lentes.

Les seuils cités ici, comme les 150 ms et les 80% de saturation du pool que surveille l'Advisor d'Aurabase Studio, sont un point de départ vérifié en code, pas une vérité universelle. Votre charge réelle reste le seul juge final. Pour dimensionner précisément max_connections plutôt que de suivre une règle générale, l'article dédié détaille la formule et ses limites.

#
Questions Fréquentes

FAQ

Trois questions qui reviennent systématiquement une fois la checklist appliquée une première fois.

Faut-il redémarrer Postgres après avoir changé une valeur de postgresql.conf ?+
Cela dépend du paramètre. max_connections et shared_buffers sont en contexte "postmaster" : redémarrage complet obligatoire. work_mem, effective_cache_size, maintenance_work_mem et la plupart des seuils d'autovacuum se rechargent à chaud avec SELECT pg_reload_conf(); ou pg_ctl reload, sans coupure de service.
Peut-on désactiver l'autovacuum pour gagner en performance ?+
Non, jamais en production. Le désactiver ne fait pas disparaître le travail de nettoyage : il s'accumule. Sans intervention, il finit par forcer un vacuum manuel ou, pire, par déclencher le wraparound d'ID de transaction qui met la base en lecture seule. Ajustez les seuils table par table plutôt que de couper le mécanisme.
À quelle fréquence revoir cette checklist ?+
À chaque changement significatif de volumétrie ou de charge, pas seulement au déploiement initial. Un schéma qui double de taille ou un trafic multiplié par trois rendent obsolètes les repères de départ ci-dessus. Notre méthodologie de benchmark backend détaille comment construire un protocole de mesure répété dans le temps plutôt qu'un audit isolé.
TUNING SANS DEVINER

Chaque projet Aurabase expose déjà ces métriques.

Requêtes lentes, connexions actives, EXPLAIN ANALYZE : l'onglet Observabilité de Studio applique une partie de cette checklist sans configuration à ajouter.

Créer un projet Guide performance
Aucune carte bancaire requise · 500 MB gratuits · 50 000 MAU