Entity Framework Arithabort, ma ancora query è lento

0

Domanda

Ho una semplice query

var count =  await _context.ExchangeRate.AsNoTracking().CountAsync(u => u.Currency == "GBP");

Il tavolo ha solo 3 Colonne e 10 righe di dati.

Quando ho provato ad eseguire la query da rete 5 progetto è di circa 2,3 secondi per la prima volta e 500ms (+- 100) per le richieste successive. Quando ho colpito la stessa richiesta in SSMS è il ritorno in quasi nessun tempo (45ms come si è visto in sql profiler).

Ho implementato ARITHABORT in EF da qui

Quando vedo in SQL Profiler è l'impostazione ARITHABORT, ma ancora la query impiega lo stesso tempo per la prima richiesta e le successive richieste.

sql profiler screen shot

Come faccio a raggiungere la stessa velocità di come SSMS velocità di esecuzione delle query. Ho bisogno di una query per eseguire molto veloce come il mio progetto ha obbligo di restituire la risposta in 1 secondo (Bisogno di fare almeno 5 semplici le chiamate al DB...se 1 chiamata di 500ms poi attraversa 1 secondo requisito)

Modifica

Provato anche con ADO.Net. Il tempo di esecuzione preso come visto in SQL Profiler è 40ms dove, come, quando si raggiunge il codice è quasi 400ms. Tanta differenza

        using (var conn = new SqlConnection(connectionString))
        {
            var sql = "select count(ExchangeRate) as cnt from ExchangeRate  where Currency = 'GBP'";

            SqlCommand cmd = new SqlCommand();

            cmd.CommandText = "SET ARITHABORT ON; " + sql;
            cmd.CommandType = CommandType.Text;
            cmd.Connection = conn;
            conn.Open();
            var t1 = DateTime.Now;
            var rd =  cmd.ExecuteReader();
            var t2 = DateTime.Now;
            TimeSpan diff = t2 - t1;

           Console.WriteLine((int)diff.TotalMilliseconds);
          
          while (rd.Read())
          {
               Console.WriteLine(rd["cnt"].ToString());
          }
            conn.Close();
        }
1

Migliore risposta

0

La tua "prima esecuzione" scenario è, generalmente, la one-off di inizializzazione statica della DbContext. Questo è dove il DbContext funziona il mapping per la prima volta e si verifica quando la prima query viene eseguita. L'approccio tipico per evitare che questo si verifichi per un utente è quello di avere un semplice "warm up" query che viene eseguita quando il servizio viene avviato.. Per esempio dopo che il vostro servizio inizializza, basta mettere qualcosa di simile al seguente:

// Warm up the DbContext
using (var context = new AppDbContext())
{
    var hasUser = context.Users.Any();
}

Questo serve anche come un rapido avviamento verificare che il database è raggiungibile e di rispondere. La query stessa di fare un'operazione rapidissima, ma il DbContext risolverà il mapping in questo momento appena generato DbContext istanze di rispondere senza incorrere in un costo che durante una richiesta.

Come per le prime prestazioni, se non è una query che dovrebbe prendere un po', e legare una richiesta, non rendono async. Le richieste asincrone sono non più veloce, in realtà sono un po ' più lento. Utilizzando async le richieste contro il DbContext è garantire il vostro web server / application thread è reattiva mentre potenzialmente costose operazioni di database sono in corso di elaborazione. Se si desidera una risposta il più rapidamente possibile, utilizzare una chiamata sincrona.

Successivamente, di verificare che tutti i campi che si sta filtrando contro, in questo caso Valuta, sono indicizzati. Avere un campo chiamato la Valuta del tuo entità come una Stringa piuttosto che un CurrencyId FK (int) indicando una Valuta è già record di un extra di indicizzazione spese con indici in numeri interi sono più piccolo/più veloce rispetto a quelli di stringhe.

Inoltre, non c'è bisogno di preoccuparsi con AsNoTracking quando si utilizza un Count query. AsNoTracking si applica esclusivamente quando si è di tornare entità (ToList/ToArray/Single/Firstecc.) per evitare di avere il DbContext trattenendo un riferimento al restituito entità. Quando si utilizza Count/Any o proiezione di ritorno proprietà da entità utilizzando Select non c'è nessuna entità restituito alla pista.

Anche prendere in considerazione la latenza di rete, tra cui il codice dell'applicazione è in esecuzione e il server di database. Sono la stessa macchina o c'è una connessione di rete in gioco? Come si può confrontare quando si esegue una query di sql server management studio? Utilizzando un profiler è possibile vedere quali SQL EF è in realtà l'invio al database. Tutto il resto in termini di tempo è un costo di: Ottenere la richiesta al DB, Ottenendo la risultante dati del richiedente, l'analisi di tale risposta. (Se nel caso in cui si sta tornando entità, l'assegnazione, la compilazione, il controllo contro riferimenti esistenti, ecc... Nel caso di conti etc. controllare i riferimenti esistenti)

Infine, per garantire che si sta ottenendo il massimo delle prestazioni, garantire che il vostro DbContexts vite sono tenuti corti. Se DbContext è tenuta aperta e che ha avuto un numero di tracking eseguire query in (Selezione di entità senza AsNoTracking) quelli monitorati i riferimenti a entità che si accumulano e possono avere un impatto negativo sulle prestazioni future query, anche se si utilizza AsNoTracking come EF cerca di controllare, attraverso di esso, tracciati riferimenti per le entità che potrebbero essere applicabili e/o connesse alla nuova query. Molte volte vedo gli sviluppatori di assumere DbContexts sono "costosi", così si opta per creare un'istanza di loro il meno possibile per evitare tali costi, solo per finire di fare le operazioni più costoso.

Con tutto considerato, EF non sarà mai veloce come materie prime SQL. Si tratta di un ORM progettato per fornire la convenienza per .Net applications quando si tratta di lavorare con i dati. Che comodità nel lavoro con le classi di entità piuttosto che sanificazione e di scrivere la propria raw SQL ogni volta che viene fornito con un costo.

2021-11-23 21:59:24

per quanto riguarda il tuo commento riguardo la latenza di Rete, sia SSMS & Net Code è nella mia macchina..db è nel server...e per le altre cose ho solo una query (questo è un POC). Così con la stessa latenza di rete di sql server management studio è in grado di recuperare in 40ms dove, come Net Code è l'assunzione di 500ms.....provato anche con ADO.NET come si è visto nella domanda, sia per assunzione di 500ms
CrazyMonk

In altre lingue

Questa pagina è in altre lingue

Русский
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................