Trova la richiesta costosa prima di cambiare il database
Parti da un’azione utente: caricamento di una categoria, ricerca in un articolo, aggiunta al carrello o invio di un ordine. Cattura il suo percorso, il numero di query, la durata sul database, le righe restituite e la durata della richiesta. Una pagina lenta può anche attendere codice applicativo o un’altra dipendenza, quindi non fare diagnosi basata solo sul tempo di caricamento della pagina.
Un piano di query è il percorso che il database percorre attraverso tabelle, indici, join, ordinamenti e aggregazioni. In PostgreSQL, EXPLAIN mostra quel percorso. EXPLAIN ANALYZE esegue l’istruzione e riporta righe e tempi effettivi, quindi usa una query rappresentativa sicura. Un ampio scarto tra stima e reale di righe è motivo di indagine sulle statistiche o sulle condizioni, non una richiesta automatica di indice.
Collega una query candidata a un percorso e un esito, così un report solo dashboard non sovrasta un checkout lento.
Registra i tempi prima della modifica e traffico comparabile senza loggare identificatori cliente, token o valori correlati alla carta.
Progetta indici per il percorso di accesso che usi davvero
Un indice è una struttura mantenuta che può aiutare a individuare righe o restituirle in ordine; non è un interruttore universale di velocità. Parti dai filtri, dalle chiavi di join e dall’ORDER BY di una query importante, poi conferma l’indice proposto in un piano. PostgreSQL documenta che un indice B-tree corrispondente può soddisfare ORDER BY senza un ordinamento separato, specialmente con un piccolo LIMIT.
Gli indici aggiungono spazio di archiviazione e lavoro di scrittura perché insert, update e delete li mantengono. Per una query che richiede una larga frazione di una tabella, una scansione sequenziale e un ordinamento esplicito possono essere più veloci. Testa su dati simili alla produzione e conserva un indice solo quando il beneficio giustifica il suo costo.
Usa i filtri reali della query e l’ORDER BY, incluso un tie-breaker deterministico quando l’interfaccia necessita ordine stabile.
Verifica se un indice viene usato e cosa costa durante le scritture; ricontrolla quando dati e traffico cambiano.
Rendi la paginazione stabile e conveniente
La paginazione per numero di pagina usa solitamente LIMIT più OFFSET. Impone sempre un ordine predicibile. PostgreSQL avverte che senza ORDER BY LIMIT può restituire un sottoinsieme imprevedibile; valori differenti di LIMIT o OFFSET possono produrre sottoinsiemi inconsistenti perché l’ottimizzatore può scegliere piani diversi.
Gli offset grandi meritano attenzione perché le righe saltate devono comunque essere calcolate. Per cataloghi profondi, cronologia ordini o navigazione in archivi, considera la paginazione cursor o keyset: richiedi righe dopo l’ultimo valore di ordinamento stabile visto e un tie-breaker unico. Definisci come appaiono nuove o eliminate registrazioni prima di cambiare l’interfaccia.
Restituisci la pagina più piccola utile piuttosto che un risultato senza limiti.
Decidi se l’interfaccia ha davvero bisogno di un totale esatto ad ogni richiesta.
Cache il lavoro di lettura senza servire risposte errate
La cache riutilizza un risultato precedente invece di ricostruirlo dal database. Parti dal layer HTTP per pagine pubbliche e ripetibili e risorse versionate, perché un hit di cache può evitare lavoro applicativo e database. web.dev raccomanda caching a lunga durata per URL versionati; cambiare l’URL è il meccanismo pratico di invalidazione.
La policy di cache è una decisione di correttezza. Una cache condivisa può riutilizzare una risposta per più utenti, quindi non condividere output specifico di account, carrello, prezzo o autorizzazione a meno che non sia progettato e testato per quello scopo. Cache-Control private limita il riuso alla cache del browser, mentre no-store indica ai cache di non conservarlo.
Separa output pubblico di catalogo o articoli da output specifico di sessione, posizione e permessi.
Definisci chi può vedere un valore obsoleto, per quanto tempo e il percorso di invalidazione o revalidazione.
Proteggi la capacità delle connessioni invece di aumentare semplicemente il tetto
Una connessione è una sessione client attiva verso il database. Worker, cron job, anteprime o retry possono esaurire gli slot anche quando singole query sembrano accettabili. max_connections di PostgreSQL controlla le connessioni concorrenti, si imposta all’avvio del server e un valore più alto alloca più risorse incluso shared memory. Aumentarlo senza un modello di carico può spostare il punto di fallimento.
Imposta un unico budget tra worker web, job background, amministrazione e repliche. Usa pooling con limiti dove si adatta, preserva margine per il recupero e applica timeout così il lavoro abbandonato non attenda indefinitamente. Numeri sicuri dipendono dal motore, memoria, mix di query e limiti del provider; confermali con l’operatore.
Includi processi web, code, task programmati, migrazioni, strumenti di reporting e job di deployment.
Limita la concorrenza e usa backoff così un guasto non moltiplichi la domanda di connessioni.
Osserva il costo delle query con contesto e controlli di privacy
Classifica il lavoro database per impatto totale, non per un singolo campione lento. Una query moderatamente lenta chiamata migliaia di volte può contare più di un report raro. pg_stat_statements di PostgreSQL aggrega dati di pianificazione ed esecuzione incluse chiamate, tempi totali e medi, righe e attività di buffer. Richiede configurazione del server e un riavvio per aggiungerlo o rimuoverlo; il tracciamento della pianificazione può aggiungere overhead.
Collega gruppi di query a percorso, versione di rilascio e finestra temporale. OpenTelemetry consiglia di raccogliere il testo della query di default solo dopo la sanificazione che sostituisce i letterali, e usare un sommario a bassa cardinalità per il raggruppamento. Questo aiuta i proprietari a vedere trend senza esportare dati cliente o creare una label per ogni valore.
Revisiona durata, tempo totale, chiamate, errori, connessioni e righe; ciascuno rivela una diversa modalità di fallimento.
Usa query parametrizzate e verifica che i letterali siano rimossi prima che tracing o log escano dall’applicazione.
Distribuisci le modifiche al database come lavoro di affidabilità reversibile
Tratta un indice, una riscrittura, una policy di cache, un’impostazione di pool o una modifica di schema come una modifica di produzione con un proprietario, una misura di successo e una decisione di rollback. Valida in un ambiente rappresentativo, rilascia a una fetta limitata e osserva il viaggio interessato. Più veloce non è successo se la modifica restituisce dati sbagliati, mancanti, duplicati o obsoleti.
Le modifiche di schema richiedono attenzione perché le versioni dell’applicazione possono sovrapporsi. La guida di Google Cloud descrive una sequenza di compatibilità: rilascia un’applicazione che gestisca vecchio e nuovo schema, cambia lo schema, poi rilascia la funzionalità che lo usa. Questo preserva una rotta di rollback applicativa. Locking e comportamento di modifica online differiscono per motore e servizio gestito; ottieni revisione qualificata per sistemi ad alto volume o legati a pagamenti.
Nomina il percorso, i segnali di performance e correttezza e la soglia che ferma il rollout.
Verifica performance e correttezza in una fetta controllata prima di allargare; esercita la rotta di ritorno al di fuori di un incidente.
