Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Le prestazioni del database sono un argomento vasto e complesso, che si estende su un intero stack di componenti: il database, la rete, il driver di database e i livelli di accesso ai dati, ad esempio EF Core. Anche se livelli di alto livello e O/RMs come EF Core semplificano notevolmente lo sviluppo di applicazioni e migliorano la manutenibilità, a volte possono essere opachi, nascondendo dettagli interni critici per le prestazioni, ad esempio l'esecuzione di SQL. Questa sezione tenta di fornire una panoramica di come ottenere buone prestazioni con EF Core e come evitare problemi comuni che possono compromettere le prestazioni dell'applicazione.
Identificare colli di bottiglia e misurare, misurare, misurare
Come sempre con le prestazioni, è importante non correre nell'ottimizzazione senza dati che mostrano un problema; come disse il grande Donald Knuth, "Ottimizzazione prematura è la radice di tutto il male". La sezione relativa alla diagnosi delle prestazioni illustra diversi modi per comprendere dove l'applicazione sta spendendo tempo nella logica del database e come individuare aree problematiche specifiche. Dopo aver identificato una query lenta, è possibile considerare le soluzioni: manca un indice nel database? È consigliabile provare altri modelli di query?
Eseguire sempre il benchmark del codice e le possibili alternative: la sezione relativa alla diagnosi delle prestazioni contiene un benchmark di esempio con BenchmarkDotNet, che è possibile usare come modello per i propri benchmark. Non presupporre che i benchmark pubblici generali si applichino as-is al caso d'uso specifico; un'ampia gamma di fattori, ad esempio latenza del database, complessità delle query e quantità effettive di dati nelle tabelle, può avere un effetto profondo sulla soluzione migliore. Ad esempio, molti benchmark pubblici vengono eseguiti in condizioni di rete ideali, in cui la latenza per il database è quasi zero e con query estremamente leggere che richiedono difficilmente alcuna elaborazione (o I/O del disco) sul lato database. Sebbene siano utili per confrontare i sovraccarichi di runtime di diversi livelli di accesso ai dati, le differenze rivelano in genere essere trascurabili in un'applicazione reale, in cui il database esegue il lavoro effettivo e la latenza per il database è un fattore significativo delle prestazioni.
Aspetti delle prestazioni di accesso ai dati
Le prestazioni generali di accesso ai dati possono essere suddivise nelle categorie generali seguenti:
- Prestazioni pure del database. Con il database relazionale, EF converte le query LINQ dell'applicazione nelle istruzioni SQL eseguite dal database; queste istruzioni SQL possono essere eseguite in modo più o meno efficiente. L'indice corretto nel posto giusto può fare un'enorme differenza nelle prestazioni SQL, oppure riscrivere la query LINQ può far sì che EF generi una query SQL migliore.
- Trasferimento dei dati di rete. Come per qualsiasi sistema di rete, è importante limitare la quantità di dati in transito. Ciò consente di assicurarsi di inviare e caricare solo i dati che saranno effettivamente necessari, ma anche di evitare l'effetto cosiddetto "esplosione cartesiana" durante il caricamento di entità correlate.
- Andata e ritorno di rete Oltre alla quantità di dati trasmessi, i viaggi di andata e ritorno della rete, poiché il tempo impiegato per l'esecuzione di una query nel database può essere oscurato dal tempo impiegato dai pacchetti per spostarsi tra la vostra applicazione e il vostro database. Il sovraccarico del round trip dipende in modo significativo dall'ambiente in uso; più lontano è il server di database, maggiore è la latenza e il costo di ogni round trip. Con l'avvento del cloud, le applicazioni si trovano sempre più lontano dal database e le applicazioni "chiacchiere" che eseguono troppi round trip hanno prestazioni ridotte. Pertanto, è importante comprendere esattamente quando l'applicazione contatta il database, il numero di roundtrips che esegue e se tale numero può essere ridotto.
- Sovraccarico del runtime di Entity Framework. Ef aggiunge infine un sovraccarico di runtime alle operazioni del database: EF deve compilare le query da LINQ to SQL (anche se in genere deve essere eseguito una sola volta), il rilevamento delle modifiche aggiunge un sovraccarico (ma può essere disabilitato) e così via. In pratica, il sovraccarico ef per le applicazioni reali è probabilmente trascurabile nella maggior parte dei casi, poiché il tempo di esecuzione delle query nel database e la latenza di rete dominano il tempo totale; ma è importante capire quali sono le opzioni e come evitare alcune insidie.
Sapere cosa sta succedendo sotto il cofano
Ef consente agli sviluppatori di concentrarsi sulla logica di business generando SQL, materializzando i risultati ed eseguendo altre attività. Come qualsiasi livello o astrazione, tende anche a nascondere ciò che sta accadendo sotto il cofano, ad esempio le query SQL effettive in esecuzione. Le prestazioni non sono necessariamente un aspetto critico di ogni applicazione, ma nelle applicazioni in cui si trova, è fondamentale che lo sviluppatore comprenda le operazioni eseguite da Entity Framework: esaminare le query SQL in uscita, seguire i round trip per assicurarsi che il problema N+1 non si verifichi e così via.
Memorizzare nella cache all'esterno del database
Infine, il modo più efficiente per interagire con un database consiste nel non interagire affatto con esso. In altre parole, se l'accesso al database viene visualizzato come collo di bottiglia delle prestazioni nell'applicazione, può essere utile memorizzare nella cache determinati risultati all'esterno del database, in modo da ridurre al minimo le richieste. Anche se la memorizzazione nella cache aggiunge complessità, è una parte particolarmente importante di qualsiasi applicazione scalabile: mentre il livello applicazione può essere facilmente ridimensionato aggiungendo altri server per gestire un maggiore carico, il ridimensionamento del livello di database è in genere molto più complicato.