Query N+1: quando l'app generata con Cursor rallenta senza motivo apparente

VibeInspect.ai · 25 agosto 2026 · 5 min di lettura
- performance
- query-n-plus-1
- cursor
- audit-codice
- vibe-coding
Il collo di bottiglia non è la banda, è il numero di richieste
Quando un'applicazione sembra lenta, il primo istinto è dare la colpa alla rete o al database sottodimensionato. Ma nella maggior parte dei casi il problema è molto più specifico. In un'analisi pubblicata su dev.to, Common network bottlenecks and how to actually find them, l'autore descrive il classico pattern N+1: "one request to get a list, then one more per item", cioè una richiesta per ottenere una lista e poi una richiesta aggiuntiva per ogni singolo elemento.
Il risultato è che un'operazione che dovrebbe richiedere un paio di round trip finisce per generarne decine. La rete è perfettamente sana. Il database regge. Eppure la pagina impiega secondi a caricare, e nessuno capisce perché. Aggiungere banda o potenza non serve a nulla: il costo è nella struttura del codice, non nell'infrastruttura.
Questo è esattamente il tipo di difetto che si annida nel codice generato in fretta, senza una revisione della logica di accesso ai dati.
Cosa significa se il tuo codice l'ha scritto Cursor
Cursor è ottimo per produrre rapidamente componenti che funzionano al primo colpo. Chiedi una pagina che mostra l'elenco degli ordini con il nome del cliente e l'assistente ti restituisce codice che gira e passa i test manuali. Il problema è come recupera i dati.
Un modello linguistico tende a scrivere codice leggibile e diretto: prende la lista degli ordini, poi per ciascun ordine fa una query separata per recuperare il cliente. Con dieci righe nel database di sviluppo tutto vola. Con diecimila righe in produzione, ogni caricamento di pagina lancia migliaia di query, una dopo l'altra.
Il codice è corretto dal punto di vista funzionale. Restituisce i dati giusti. Ma nasconde un pattern N+1 che scala malissimo, e nessuno lo vede finché non arrivano gli utenti veri e i tempi di risposta esplodono. Cursor non ha eseguito il tuo codice sotto carico: ha solo prodotto qualcosa di plausibile.
La questione non è aver usato l'AI. La questione è che tra "funziona sul mio schermo" e "regge in produzione" c'è un abisso che nessuno strumento di generazione riempie da solo.
Perché ora ti serve un audit
Un pattern N+1 è invisibile finché il volume di dati resta piccolo. È una bomba a orologeria: cresce insieme al tuo prodotto e si manifesta proprio quando hai più utenti, cioè nel momento peggiore. E raramente arriva da solo. Dove c'è una query N+1, spesso ci sono anche indici mancanti, chiamate ripetute a servizi esterni dentro un ciclo, o dati caricati per intero quando ne servirebbe una porzione.
Un audit indipendente serve a rispondere a una domanda che nessun test funzionale copre: come si comporta questo codice quando i numeri diventano seri?
VibeInspect è un audit on-demand: carichi lo ZIP del repository, alcuni specialisti AI analizzano il codice e ricevi un PDF con un verdetto. Non gira su un tuo server, non è un pentest e non modifica il codice. Il sorgente viene cancellato al termine dell'analisi.
Qui la differenza tra i piani conta. Con VibeInspect puoi scegliere Diagnostic quando hai un sospetto tecnico preciso, come un rallentamento inspiegabile: ottieni file, riga ed evidenze del punto in cui il pattern N+1 si nasconde. Non correzioni automatiche e non revisione umana, ma la mappa esatta di dove intervenire. Se invece la tua domanda è più ampia, "non so davvero in che stato sia il repository", il piano Snapshot ti dà uno score e un verdetto generale.
Cosa un linter non vede
È facile pensare che un linter avrebbe segnalato il problema. Non lo fa, e per un motivo strutturale. Un linter analizza il testo del codice: stile, variabili non usate, formattazione, qualche antipattern sintattico. Non capisce cosa succede a runtime.
Un pattern N+1 è codice sintatticamente impeccabile. Un ciclo che al suo interno esegue una query è, riga per riga, perfettamente valido. Il linter non ha idea di quante volte quel ciclo verrà eseguito, né di quanti dati ci saranno nella tabella, né del fatto che ogni iterazione apre un round trip verso il database. Vede una funzione ben scritta e passa oltre.
La stessa cecità riguarda altri difetti che dipendono dal comportamento e dal contesto, non dalla sintassi:
- il numero effettivo di round trip che un'operazione genera;
- la differenza tra un dataset di test e un carico reale;
- l'assenza di paginazione su un elenco che crescerà indefinitamente;
- chiamate ripetute a un servizio esterno dentro un loop.
Sono tutte cose che si vedono solo ragionando sul funzionamento dell'applicazione, non sul suo formato. Ed è precisamente questo il vuoto che un audit orientato al comportamento del codice va a coprire.
Cosa fare questa settimana
Non aspettare che siano gli utenti a dirti che l'app è lenta. Fai tre cose concrete nei prossimi giorni:
- Individua le pagine che mostrano liste. Elenchi di ordini, prodotti, messaggi, utenti: sono i candidati naturali per il pattern N+1. Apri il codice che le popola e conta le query.
- Prova con dati realistici. Popola il database di sviluppo con migliaia di righe, non con dieci, e misura il tempo di caricamento. Se cresce in modo lineare con il numero di elementi, hai trovato il tuo N+1.
- Fai analizzare il repository da fuori. Un occhio esterno vede ciò a cui ti sei abituato. Un audit ti dice dove il codice regge e dove cederà sotto carico, prima che accada.
Se hai costruito con Cursor e senti che qualcosa rallenta senza una causa evidente, non tirare a indovinare. Carica lo ZIP su VibeInspect e chiedi un audit Diagnostic: file, riga ed evidenze del punto esatto in cui il tuo codice sta pagando la latenza a ogni round trip.
Domande frequenti
Cos'è il pattern N+1?
È quando il codice esegue una query per ottenere una lista e poi una query aggiuntiva per ogni singolo elemento. Con pochi dati non si nota, ma su volumi reali genera decine o migliaia di round trip, rallentando drasticamente l'applicazione.
Perché un linter non trova le query N+1?
Un linter analizza la sintassi del codice, non il suo comportamento a runtime. Un ciclo che contiene una query è formalmente corretto, quindi il linter lo lascia passare senza sapere quante volte verrà eseguito o quanti dati ci saranno.
VibeInspect corregge il codice lento?
No. VibeInspect analizza il repository e restituisce un verdetto con evidenze. Non modifica il codice, non è un pentest e non offre revisione umana fuori dal piano Assurance. Con Diagnostic ottieni file, riga ed evidenze del problema.
Quale piano scelgo per un problema di prestazioni?
Se hai un sospetto tecnico preciso, come un rallentamento, scegli Diagnostic a 499 euro: ricevi file, riga ed evidenze. Se invece vuoi solo capire lo stato generale del repository, Snapshot a 49 euro ti dà uno score e un verdetto complessivo.