Trouver la requête coûteuse avant de modifier la base
Commencez par une action utilisateur : chargement de catégorie, recherche d’article, ajout au panier ou soumission de commande. Capturez son parcours, le nombre de requêtes, la durée en base, les lignes retournées et la durée de la requête. Une page lente peut aussi attendre du code applicatif ou une autre dépendance, donc ne diagnostiquez pas uniquement d’après le temps de chargement de la page.
Un plan de requête est le chemin que la base emprunte à travers tables, index, jointures, tris et agrégations. Dans PostgreSQL, EXPLAIN montre ce chemin. EXPLAIN ANALYZE exécute l’instruction et rapporte les lignes et temps réels ; utilisez donc une requête représentative et sans danger. Un grand écart estimation/actuel de lignes est une raison d’investigation des statistiques ou des conditions, pas une demande d’index automatique.
Reliez une requête candidate à une route et un résultat, pour qu’un rapport de tableau de bord ne supplante pas un checkout lent.
Enregistrez les timings avant changement et un trafic comparable sans consigner d’identifiants clients, tokens ou valeurs liées aux cartes.
Concevoir les index pour le chemin d’accès réellement utilisé
Un index est une structure maintenue qui aide à localiser des lignes ou à les retourner dans l’ordre ; ce n’est pas un commutateur universel de vitesse. Commencez par les filtres, clés de jointure et l’ordre d’un ensemble de requêtes important, puis confirmez l’index proposé dans un plan. PostgreSQL documente qu’un index B-tree correspondant peut satisfaire ORDER BY sans tri séparé, en particulier avec un petit LIMIT.
Les index ajoutent stockage et travail d’écriture car les INSERT, UPDATE et DELETE les maintiennent. Pour une requête qui nécessite une grande fraction d’une table, un parcours séquentiel (sequential scan) et un tri explicite peuvent être plus rapides. Testez sur des données proches de la production et conservez un index seulement quand le bénéfice justifie son coût.
Utilisez les filtres réels de la requête et le ORDER BY, y compris un tie-breaker déterministe lorsque l’interface exige un ordre stable.
Vérifiez si un index est utilisé et quel est son coût lors des écritures ; recontrôlez au fur et à mesure que les données et le trafic évoluent.
Rendre la pagination stable et abordable
La pagination par numéro de page utilise habituellement LIMIT plus OFFSET. Imposer toujours un ordre prévisible. PostgreSQL avertit que sans ORDER BY, LIMIT peut renvoyer un sous-ensemble imprévisible ; des valeurs LIMIT ou OFFSET différentes peuvent produire des sous-ensembles incohérents parce que l’optimiseur peut choisir des plans différents.
Les grands offsets méritent une attention car les lignes sautées doivent quand même être calculées. Pour la navigation profonde dans un catalogue, l’historique de commandes ou des archives, envisagez la pagination par curseur ou keyset : demander les lignes après la dernière valeur d’ordre stable vue et un tie-breaker unique. Définissez comment les enregistrements nouveaux ou supprimés apparaissent avant de changer l’interface.
Retournez la plus petite page utile plutôt qu’un résultat non borné.
Décidez si l’interface a vraiment besoin d’un total exact à chaque requête.
Cacher le travail en lecture sans servir la mauvaise réponse
La mise en cache réutilise un résultat précédent au lieu de le reconstruire depuis la base. Commencez au niveau HTTP pour les pages publiques répétables et les ressources versionnées, car un hit de cache peut éviter le travail applicatif et base. web.dev recommande une mise en cache longue pour les URLs versionnées ; changer l’URL est le mécanisme pratique d’invalidation.
La politique de cache est une décision de correction. Un cache partagé peut réutiliser une réponse entre utilisateurs, donc ne partagez pas la sortie spécifique au compte, panier, prix ou autorisation à moins qu’elle soit conçue et testée pour cette portée. Cache-Control private restreint la réutilisation au cache du navigateur, tandis que no-store ordonne aux caches de ne pas la retenir.
Séparez la sortie publique du catalogue ou des articles de la sortie session-spécifique, dépendante de la localisation et sensible aux permissions.
Définissez qui peut voir une valeur obsolète, pendant combien de temps, et le chemin d’invalidation ou de revalidation.
Protéger la capacité de connexions plutôt qu’augmenter le plafond
Une connexion est une session cliente active vers la base. Workers, cron jobs, aperçus ou tentatives de nouvelle exécution peuvent épuiser les slots même quand les requêtes individuelles semblent acceptables. Le paramètre max_connections de PostgreSQL contrôle les connexions concurrentes, est fixé au démarrage du serveur, et une valeur plus élevée alloue plus de ressources incluant la mémoire partagée. L’augmenter sans modèle de charge peut déplacer l’échec.
Fixez un budget unique entre web workers, jobs en arrière-plan, administration et réplicas. Utilisez du pooling borné quand il convient, préservez de la marge pour la récupération et appliquez des timeouts afin qu’un travail en rade n’attende pas indéfiniment. Les valeurs sûres dépendent du moteur, de la mémoire, du mix de requêtes et des limites du fournisseur ; confirmez-les avec l’opérateur.
Incluez processus web, queues, tâches planifiées, migrations, outils de reporting et jobs de déploiement.
Capper la concurrence et utiliser un backoff pour qu’une faute ne multiplie pas la demande de connexions.
Observer le coût des requêtes avec contexte et contrôles de confidentialité
Classez le travail en base par impact total, pas par un seul échantillon lent. Une requête modérément lente appelée des milliers de fois peut peser plus qu’un rapport rare. pg_stat_statements de PostgreSQL agrège données de planification et d’exécution incluant appels, temps total et moyen d’exécution, lignes et activité de buffers. Il nécessite une configuration serveur et un redémarrage pour être ajouté ou retiré ; le suivi de planification peut ajouter un overhead.
Reliez des groupes de requêtes à la route, à la version de release et à une fenêtre temporelle. OpenTelemetry conseille de collecter le texte de requête par défaut uniquement après une sanitization qui remplace les littéraux, et d’utiliser un résumé de requête à faible cardinalité pour le grouping. Cela aide les responsables à voir les tendances sans exporter de données clients ni créer une étiquette pour chaque valeur.
Revoir durée, temps total, appels, erreurs, connexions et lignes ; chacun expose un mode de défaillance différent.
Utilisez des requêtes paramétrées et vérifiez que les littéraux sont retirés avant que traces ou logs quittent l’application.
Livrer les changements de base comme du travail de fiabilité réversible
Traitez un index, une réécriture, une politique de cache, un réglage de pool ou un changement de schéma comme un changement en production avec un propriétaire, une mesure de succès et une décision de rollback. Validez dans un environnement représentatif, déployez sur une tranche limitée et surveillez le parcours affecté. Plus rapide n’est pas un succès si le changement renvoie des données erronées, manquantes, dupliquées ou périmées.
Les changements de schéma demandent de la prudence car des versions d’application peuvent coexister. Les recommandations de Google Cloud décrivent une séquence compatible : déployer une application qui gère l’ancien et le nouveau schéma, changer le schéma, puis déployer la fonctionnalité qui l’utilise. Cela préserve une route de rollback applicatif. Les comportements de verrouillage et de modification en ligne diffèrent selon le moteur et le service managé ; obtenez une revue qualifiée pour les systèmes à fort volume ou liés aux paiements.
Nommez la route, les signaux de performance et de correction, et le seuil qui arrête le déploiement.
Vérifiez performance et correction sur une tranche contrôlée avant d’élargir ; pratiquez le chemin de retour en dehors d’un incident.
