Postgres 16 vs 17 (vs 18) : quelles améliorations de performance retenir
Postgres 17 n'est pas « plus rapide » que Postgres 16 sur un vague ensemble de requêtes. Le gain réel tient à deux chantiers précis : la mémoire consommée par VACUUM sur les grosses tables, et la contention sur les connexions à forte concurrence. Postgres 18, sorti fin 2025, ajoute un changement plus profond encore : l'entrée-sortie asynchrone. Voici ce que ces versions changent vraiment, avec leurs sources, et pourquoi Aurabase tourne aujourd'hui encore en Postgres 16 en production malgré ça.
Cet article s'appuie sur la documentation officielle du projet PostgreSQL et sur deux analyses techniques publiées après chaque sortie majeure, Microsoft Tech Community (équipe Azure Database for PostgreSQL) et Crunchy Data. Aucun chiffre ci-dessous n'est un benchmark reproduit par nos soins : quand une donnée vient d'un tiers, on l'indique, avec sa source et sa date. Pour la méthodologie qu'on applique à nos propres mesures, voir notre pilier Méthodologie de benchmark.
- Le principal gain de Postgres 17 est la refonte mémoire de VACUUM (structure TidStore), qui supprime l'ancien plafond d'environ 1 Go. Les notes de version officielles indiquent jusqu'à 20x moins de mémoire utilisée dans certains cas.
- Postgres 17 réduit aussi la contention sur le calcul des snapshots de transaction, ce qui profite surtout aux instances à forte concurrence sur du matériel multi-cœurs.
- Postgres 18 (fin septembre 2025) introduit l'E/S asynchrone (AIO), le changement d'architecture le plus structurel depuis plusieurs versions majeures, en particulier pour le stockage à latence élevée.
- Postgres 18 ajoute aussi le skip scan sur index B-tree multi-colonnes, les colonnes générées virtuelles par défaut, et le support OAuth 2.0 pour l'authentification.
- Aurabase tourne en Postgres 16.15 en production aujourd'hui, vérifié dans le code : pas un retard, un choix documenté lié à l'irréversibilité des montées de version majeure sous CloudNativePG.
Ce qui change réellement entre Postgres 16, 17 et 18
Les trois versions ne se distinguent pas par un chiffre unique de performance globale. Chacune corrige un point précis de l'architecture, avec un public différent à chaque fois : les grosses tables pour Postgres 17, le stockage à latence élevée pour Postgres 18. Le tableau ci-dessous résume les faits vérifiables, tous datés, avant d'entrer dans le détail de chaque chantier.
Sources : notes de version officielles du projet PostgreSQL (postgresql.org), recoupées avec les analyses publiées par Microsoft Tech Community et Crunchy Data après chaque sortie majeure. Consulté le 24 août 2026.
La refonte mémoire de VACUUM change la donne sur les grosses tables
Avant Postgres 17, VACUUM stockait la liste des tuples morts à nettoyer dans un tableau simple, dimensionné par maintenance_work_mem. Le problème n'était pas la vitesse du calcul, mais la structure elle-même : ce tableau plafonnait autour d'1 Go, quelle que soit la valeur configurée au-delà. Sur une table avec plus d'environ 178 millions de lignes mortes, VACUUM devait boucler en plusieurs passes, chacune relisant les index en entier.
Postgres 17 remplace ce tableau par une structure appelée TidStore, un arbre radix adaptatif qui compresse fortement l'espace nécessaire pour stocker les identifiants de tuples. Les notes de version officielles du projet indiquent une réduction de la mémoire utilisée par VACUUM allant jusqu'à 20 fois dans certains cas, sans le plafond artificiel lié à l'ancienne structure. Source : notes de version officielles PostgreSQL 17, postgresql.org, 26 septembre 2024. Microsoft Tech Community et Crunchy Data ont chacun publié une analyse technique de ce changement peu après la sortie. Les deux confirment l'intérêt concret pour les tables de plusieurs centaines de millions de lignes, avec un fort taux de suppression ou de mise à jour.
Ce chantier profite surtout à un scénario précis : une table volumineuse avec un fort taux de suppression ou de mise à jour. VACUUM y tournait auparavant en plusieurs passes, faute de mémoire disponible. Sur une petite table, ou sur une charge majoritairement en lecture, le gain reste marginal, voire invisible.
Moins de contention sur les connexions à forte concurrence
Le second chantier de Postgres 17 touche un point plus discret : le calcul des snapshots de transaction. Chaque requête a besoin de savoir quelles autres transactions sont en cours pour appliquer les règles de visibilité MVCC de Postgres. Sur une machine à fort nombre de cœurs et de connexions actives, ce calcul générait de la contention sur une structure interne partagée. C'est un goulot documenté de longue date par les contributeurs du projet.
Postgres 17 réduit cette contention. L'effet se mesure surtout sur des instances à forte concurrence, avec beaucoup de connexions actives simultanées sur du matériel multi-cœurs. Sur une charge à faible concurrence, la différence avec Postgres 16 reste marginale : c'est un chantier de scalabilité, pas une baisse de latence par requête isolée.
Ce gain ne remplace pas un pooler de connexions, il en réduit simplement le coût interne. Si le nombre de connexions actives est déjà votre goulot d'étranglement, la version majeure passe au second plan. Notre guide de tuning max_connections et notre comparatif mode transaction PgBouncer creusent ce sujet plus en détail.
L'E/S asynchrone : le changement d'architecture le plus profond depuis des années
Postgres 18, sorti fin septembre 2025, s'attaque à un problème plus structurel. Jusque-là, chaque lecture disque de Postgres bloquait le processus qui l'avait demandée. Le nouveau sous-système d'entrée-sortie asynchrone (AIO) permet à un processus de lancer plusieurs lectures en parallèle et de continuer à travailler pendant qu'elles se terminent, au lieu d'attendre chacune séquentiellement.
Le paramètre io_method contrôle ce comportement : worker (des processus dédiés à l'E/S, valeur par défaut) ou io_uring sur Linux, quand Postgres a été compilé avec ce support. Les scans séquentiels, les scans bitmap heap et VACUUM sont les premiers bénéficiaires, en particulier sur du stockage à latence élevée : disques réseau, volumes cloud, plutôt que du NVMe local.
PlanetScale, qui propose une offre Postgres managée, a publié ses propres comparatifs Postgres 17 vs 18 centrés sur ce changement d'E/S. Ce sont leurs mesures sur leur propre infrastructure, pas des chiffres qu'on a reproduits indépendamment ici. À prendre comme un signal que le sujet mérite d'être testé sur votre charge réelle, pas comme un pourcentage universel.
L'AIO généralisée de Postgres 18 prolonge un chantier amorcé en Postgres 17, pas un changement isolé. La version 17 avait déjà introduit l'interface de streaming I/O, mais limitée à ANALYZE et aux scans séquentiels. Postgres 18 étend cette même logique à un périmètre plus large d'opérations, dont VACUUM et les scans bitmap heap. Les deux versions se lisent donc comme une progression, pas comme deux paris distincts sur l'E/S.
Les autres changements qui comptent
Trois autres changements de Postgres 18 méritent d'être suivis, même s'ils ne portent pas directement sur la performance brute.
Le skip scan sur index B-tree multi-colonnes permet à Postgres d'utiliser un index composite même quand la requête ne filtre pas sur sa colonne de tête. Avant Postgres 18, ce cas de figure imposait souvent un scan complet de la table, ou la création d'un index dédié supplémentaire.
Les colonnes générées virtuelles (GENERATED ALWAYS AS (...) VIRTUAL) deviennent le comportement par défaut quand STORED n'est pas précisé. Une colonne virtuelle se calcule à la lecture plutôt que d'être écrite sur disque, ce qui réduit le volume écrit à chaque insertion ou mise à jour de la ligne source.
Postgres 18 ajoute enfin le support d'OAuth 2.0 côté authentification (RFC 8628, device flow), aux côtés des mécanismes existants comme SCRAM, les certificats ou LDAP. Un point pertinent pour toute organisation qui centralise déjà ses identités via un fournisseur OAuth/OIDC externe.
Pourquoi Aurabase tourne encore en Postgres 16, et ce qui ferait basculer ce choix
Chez Aurabase, la base tenant tourne aujourd'hui en Postgres 16.15, pas en 17. C'est vérifiable directement dans le dépôt : l'image CNPG de référence (docker/Postgres.CNPG.Dockerfile) part de ghcr.io/cloudnative-pg/postgresql:16-standard-bookworm, épinglée par digest, la même version majeure que le tier partagé (docker/Postgres.Dockerfile). Vérifié le 24 août 2026.
Le code documente aussi pourquoi. Un commentaire de correction dans k8s_tenant.rs explique qu'un repli antérieur pointait par erreur vers postgresql:17.2. Le motif invoqué à l'époque, l'image standard n'embarquerait pas pgvector, s'est révélé faux à la vérification. Les deux images embarquent pgvector : 0.8.0 sur la 17.2, 0.8.5 sur la 16-standard-bookworm mesurée sur le cluster de flotte.
Le vrai risque, documenté dans le commentaire lui-même, est ailleurs : CloudNativePG interdit toute rétrogradation de version majeure une fois un Cluster créé. Une flotte provisionnée par erreur en Postgres 17 serait irréversible, alors que tout ce qui a été validé de bout en bout chez Aurabase l'a été en Postgres 16.
Ce n'est pas un jugement sur Postgres 17 en tant que tel. C'est une politique de prudence opérationnelle : ne pas basculer une flotte de production vers une version majeure tant que la validation de bout en bout n'a pas suivi. Le même raisonnement s'applique à toute équipe qui gère du Postgres via CloudNativePG ou un opérateur Kubernetes équivalent. La question n'est pas seulement le gain de performance attendu, c'est aussi le chemin retour si quelque chose ne va pas.
pg_upgrade migre dans un seul sens, et CloudNativePG applique la même contrainte au niveau de son opérateur. Le seul chemin de retour consiste à restaurer une sauvegarde antérieure à la mise à jour, ou repartir d'une instance neuve dans l'ancienne version.Faut-il migrer vers Postgres 17 ou 18 dès maintenant ?
Trois critères permettent de trancher sans attendre un chiffre universel. D'abord, la taille et le taux de mutation de vos plus grosses tables : si VACUUM tourne déjà en plusieurs passes, le chantier mémoire de Postgres 17 s'applique directement à votre cas. Ensuite, votre stockage : sur du SSD local à faible latence, l'E/S asynchrone de Postgres 18 apporte moins que sur un volume réseau. Enfin, votre chemin de retour : sur un opérateur qui interdit le downgrade majeur, tester d'abord sur un environnement jetable n'est pas une précaution optionnelle.
Concrètement, la même règle vaut pour n'importe quelle flotte gérée par un opérateur Kubernetes. Provisionnez d'abord un cluster de test dans la version cible, puis rejouez-y une charge représentative de votre production. Ne touchez au cluster réel qu'une fois ce test validé de bout en bout, pas seulement sur la lecture des notes de version. Si votre arbitrage porte aussi sur le choix entre base dédiée et base mutualisée pour absorber ce type de changement, notre article base dédiée vs mutualisée creuse cet angle.
Ce qu'on nous demande le plus souvent
La performance compte moins que la réversibilité
Le choix entre Postgres 16, 17 et 18 ne se résume pas à une version « la plus rapide ». Postgres 17 corrige un vrai problème structurel de VACUUM sur les grosses tables et réduit la contention à forte concurrence. Postgres 18 va plus loin avec l'E/S asynchrone, un changement d'architecture qui demande d'être testé sur votre charge et votre stockage réels avant d'être généralisé.
Le critère le plus souvent oublié n'est pas la performance, c'est la réversibilité. Sur un opérateur comme CloudNativePG, une montée de version majeure ne se défait pas après coup. Avant de basculer une flotte de production, la vraie question n'est pas seulement le gain attendu, c'est aussi le chemin retour si le test échoue. Si vous préparez cette montée de version, notre checklist de tuning Postgres en production détaille les réglages à revalider après un changement de version majeure.