M365Con 2027 – conferenza online gratuita · 11–22 Jan 2027 · 120 sessions→ m365con.net

Blog · Mirko Peters

Risolvere una volta per tutte il problema delle query N+1

By ·

Bentornati, colleghi sviluppatori! Se avete mai costruito un'applicazione con Entity Framework Core, è probabile che vi siate imbattuti in colli di bottiglia nelle prestazioni che vi hanno lasciato a grattarvi la testa. Perché una query che funziona al volo in sviluppo si blocca in produzione? Spesso il colpevole si nasconde proprio sotto gli occhi di tutti: il famigerato problema delle query N+1.

Automatically translated with AI from the original post. Read the English original

▶ BLOGConquering the N+1 QueryProblem Once and For AllM365.FM
Titelbild: Conquering the N+1 Query Problem Once and For All

Bentornati, colleghi sviluppatori! Se avete mai costruito un'applicazione con Entity Framework Core, è probabile che vi siate imbattuti in colli di bottiglia nelle prestazioni che vi hanno lasciato a grattarvi la testa. Perché una query che funziona al volo in sviluppo si blocca in produzione? Spesso il colpevole si nasconde proprio sotto gli occhi di tutti: il famigerato problema delle query N+1. In questo post approfondiremo che cosa causa questo killer silenzioso delle prestazioni, come rilevarlo prima che se ne accorgano gli utenti e come risolverlo in modo efficace con il caricamento eager, le proiezioni e alcune tecniche di ottimizzazione intelligenti.

Prima di entrare nei dettagli tecnici, non perdetevi l'episodio del podcast correlato: Improve Entity Framework Core Query Performance. In quella puntata analizziamo diverse trappole comuni di Entity Framework e condividiamo consigli pratici per far girare le vostre applicazioni a velocità fulminea.

Capire il problema delle query N+1

Che cos'è N+1?

Il problema N+1 si verifica quando si caricano dati correlati in un modo che genera moltissime query aggiuntive. In Entity Framework Core questo spesso accade quando si accede ai dati correlati all'interno di un ciclo. Per esempio, potreste recuperare 100 ordini. Poi, per ogni ordine, accedete alla proprietà del cliente. Questo genera una query per tutti gli ordini e altre 100 query, una per ogni cliente. Alla fine ne eseguite 101 invece di una sola. Questo rallenta l'applicazione, soprattutto quando i dati sono molti. Con dataset di piccole dimensioni il problema può passare inosservato, ma in produzione diventa un grosso ostacolo.

Rilevare le query N+1 in produzione

Il problema N+1 si individua osservando quante query l'applicazione invia al database. Ecco alcuni modi per rilevarlo:

  • Abilitate il logging SQL per vedere ogni query eseguita.
  • Usate gli strumenti di profilazione per verificare le prestazioni delle query.
  • Monitorate il numero di query. Se per un risultato di piccole dimensioni vedete molte query, potreste avere un problema N+1.
  • Testate l'applicazione con grandi volumi di dati, simili a quelli di produzione.

Suggerimento: controllate sempre i log e gli strumenti di profilazione dopo aver aggiunto nuove query o modificato il modo in cui caricate i dati correlati.

Risolvere N+1 con il caricamento eager

Potete risolvere il problema N+1 in Entity Framework Core usando il caricamento eager. Il caricamento eager permette di recuperare tutti i dati necessari in una sola query. Si fa usando il metodo Include. In questo modo EF unisce le tabelle correlate e ottiene tutto in una volta. Per esempio, se volete ottenere autori e relativi libri, potete scrivere:

var authorsWithBooks = context.Authors.Include(a => a.Books).ToList();

Questo codice esegue una singola query che unisce autori e libri. L'applicazione ottiene tutti i dati in un colpo solo. Il caricamento eager riduce il numero di query e rende l'applicazione più veloce. Conviene usarlo quando si sa di aver bisogno subito dei dati correlati. Così si evitano rallentamenti e l'applicazione continua a funzionare senza intoppi.

Tracking e no-tracking per le prestazioni

Entity Framework Core tiene traccia di ogni entità caricata. È l'impostazione predefinita. Il tracking permette a EF di sapere se modificate qualcosa. Tuttavia può rallentare l'applicazione, ed è più lento con dataset di grandi dimensioni. Potreste notare un consumo di memoria più elevato. Le query possono anche richiedere più tempo quando il tracking è attivo. Usare AsNoTracking rende le query più veloci e riduce il consumo di memoria. L'applicazione risponde più rapidamente e può servire più utenti contemporaneamente.

Suggerimento: se disattivate il tracking, le query vengono eseguite più velocemente. È la scelta migliore quando serve solo leggere i dati.

Usa asnotracking se non vuoi aggiornare o eliminare i dati. La maggior parte delle API web si limita a leggere dati. Circa il 70-80% degli endpoint mostra solo informazioni. Questi lavorano meglio con asnotracking. Ecco alcuni buoni casi in cui usarlo:

  • Report e dashboard che mostrano solo dati
  • Risposte API che restituiscono elenchi o dettagli da visualizzare
  • Endpoint di ricerca o filtro che leggono solo dal database

Paginazione e grandi set di dati

Quando usi EF con grandi quantità di dati, possono sorgere seri problemi. Caricare troppi dati in una sola volta può rallentare l'app o addirittura mandarla in crash. Ecco alcune conseguenze possibili:

  • La tua app potrebbe consumare troppa memoria e finire senza risorse.
  • Ottenere le risposte può richiedere molto tempo perché i dati sono troppi.
  • Il database potrebbe smettere di funzionare se provi a caricare troppi dati in una sola volta.

Puoi risolvere questi problemi usando la paginazione. La paginazione divide i dati in porzioni più piccole. Questo rende l'app più veloce e più semplice da usare. In EF puoi farlo con Skip() e Take(). Skip ti permette di saltare alcuni record. Take recupera solo il numero di record che desideri. Così lavori con grandi quantità di dati e l'app resta reattiva.

Operazioni bulk e batching

Puoi rendere il database più veloce con le operazioni bulk. Questi metodi permettono di modificare molti record contemporaneamente. I metodi standard di EF vanno bene per lavori piccoli, ma diventano lenti con grandi volumi di dati. Le operazioni bulk ti aiutano a inserire, aggiornare o eliminare migliaia di righe rapidamente. Possono servire quando importi dati da file CSV, quando sincronizzi record o per gli aggiornamenti notturni.

Il batching ti permette di raggruppare le operazioni così l'app lavora più velocemente. Puoi usare aggiornamenti batch con UpdateRange() per modificare molti elementi in una volta sola. Evita di chiamare SaveChanges() troppo spesso, perché ogni chiamata invia dati al database. EF Core 7 introduce nuovi metodi come ExecuteUpdate e ExecuteDelete per le modifiche in blocco.

Conclusioni

Ottimizzare Entity Framework Core non deve essere un esercizio di intuito. Capendo come si genera il problema N+1, usando gli strumenti per monitorare il SQL generato, sfruttando il caricamento eager e le query no-tracking, e integrando paginazione e operazioni bulk, puoi trasformare un livello dati lento in un motore ad alte prestazioni. Misura sempre la baseline delle prestazioni e testa le query in modo approfondito in condizioni realistiche.

Per approfondire queste strategie, ascolta l'episodio di approfondimento su Improve Entity Framework Core Query Performance. Applicare queste buone pratiche eviterà che le tue applicazioni incappino in colli di bottiglia nascosti e garantirà un'esperienza fluida per i tuoi utenti!

Entities in this article

Entity Framework Core

RSS