Quand un cache de lignes PostgreSQL aide
Une base de données peut servir chaque page depuis la mémoire tout en passant du temps à exécuter les requêtes, vérifier la visibilité et construire les résultats. Un cache de lignes essaie d’éviter une partie de ce travail répété. Il ajoute aussi la gestion des clés, les vérifications du cache et les coûts de sérialisation. La bonne question est de savoir si la requête applicative complète devient moins coûteuse pour votre charge.
Note de version du 04/10/2026 : L’API SQL
local_cache.mget(regclass, anyarray)de 2.x a été supprimée en 3.0.0 ; utilisez RESPMGETpour lire les lignes.
pg_local_cache propose un endpoint RESP MGET explicite pour lire des lignes complètes. Les requêtes SELECT ordinaires conservent leur chemin d’exécution PostgreSQL habituel. Un cache shared_buffers chaud et un cache de lignes chaud sont donc des conditions expérimentales différentes.
Écrire d’abord le contrat de résultat
Comparez les mêmes clés, colonnes et formes de sortie. Si l’application n’a besoin que de deux colonnes, comparer cette projection SQL à des lignes complètes sérialisées mesure des travaux différents. Si les appelants attendent des doublons, l’ordre d’entrée et un résultat nul pour chaque clé absente, incluez ce travail d’alignement dans chaque client.
Le code source conservé de l’exemple Node.js
contient la référence préparée ANY et une fonction qui restaure les positions
d’entrée. L’exemple ordonné WITH ORDINALITY
montre la gestion des positions en SQL. Aucun des deux n’exige l’extension.
Modifier une seule dimension de charge à la fois
| Expérience | Ce qui reste fixe | Ce que cela révèle |
|---|---|---|
| Lectures chaudes répétées | Clés, forme du résultat, connexions | Réutilisation d’entrées déjà remplies |
| Clés froides ou absentes | Distribution des requêtes et taille du lot | Coûts de la table source et des résultats négatifs |
| Lots plus grands | Nombre total de clés demandées et forme de la charge utile | Économies d’allers-retours contre travail par clé |
| Écritures concurrentes | Mélange lecture/écriture et limites transactionnelles | Coûts d’invalidation, de remplissage et de visibilité |
| Lignes plus larges | Distribution des clés et placement du client | Coûts de sérialisation, de transport et contournement lié à la taille |
Une lecture inéligible peut légitimement utiliser la table source. Inspectez les
variations de compteurs autour de chaque expérience ; un faible taux de hits ne
permet pas à lui seul de diagnostiquer une installation défaillante. Gardez les
compteurs SQL et RESP séparés. La référence technique
décrit local_cache.stats() et local_cache.health().
Utiliser le runner partagé, puis inspecter les preuves
Après le démarrage rapide, exécutez la comparaison du dépôt :
./examples/benchmark.sh all > comparison.json
python3 scripts/benchmark_report.py comparison.json
Le guide des benchmarks liste les prérequis, les contrôles de charge et les métriques. Conservez le JSON brut. Enregistrez les révisions de l’extension et du harnais, la version PostgreSQL, la machine, le nombre de connexions et le placement du client. Comparez les exécutions répétées, les distributions de latence et les ressources serveur avec le débit. Un court smoke test de correction n’est pas un résultat de vitesse publiable.
Décider depuis la limite applicative
SQL préparé et RESP MGET utilisent des chemins de lecture et un traitement des résultats différents. Un gain pour l’un ne prouve pas un gain pour l’autre. Mesurez chaque chemin avec le profil réel des requêtes de votre application ; un résultat ne prédit pas les performances de toutes les charges.
Gardez le SQL ordinaire lorsque des jointures, projections, verrous ou formes de tables non prises en charge sont nécessaires, ou si le cache n’apporte aucun bénéfice mesuré. Pour des lectures répétées de lignes complètes par clé primaire, testez RESP MGET avec le même travail client que celui effectué par votre application. Consultez le guide de décision sur la mise en cache et l’expérience d’invalidation.