Entity Framework Arithabort jest WŁĄCZONY, ale na żądanie nadal działa powoli

0

Pytanie

Mam proste pytanie

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

Tabela zawiera tylko 3 kolumny i 10 wierszy danych.

Kiedy próbowałem wykonać żądania z projektu Net 5, pierwszy raz to trwało około 2,3 sekundy, a dla kolejnych żądań-500 ms (+- 100). Kiedy wykonuję to samo zapytanie w SSMS, wraca prawie natychmiast (45 ms, jak pokazano w sql profiler).

Osiągnąłem ARITHABORT w EF stąd

Kiedy widzę w SQL Profiler, że określa on ARITHABORT, ale nadal zapytanie zajmuje tyle samo czasu dla pierwszego zapytania i żądania.

sql profiler screen shot

Jak mi się osiągnąć prędkość jest taka sama, jak prędkość zapytań SSMS. Potrzebuję, aby wniosek był wykonywany bardzo szybko, tak jak w moim projekcie jest wymóg zwrócić odpowiedź w ciągu 1 sekundy (należy zrobić co najmniej 5 prostych połączeń BAZY danych...jeśli 1 wyzwanie zajmuje 500 ms, to on przecina wymóg w 1 sekundę)

Edytuj

Próbowałem nawet z ADO.Net. Czas realizacji, jak widać z programu SQL Profiler, wynosi 40 ms, gdzie, jak i w przypadku z kodem, to jest prawie 400 ms. Tak wiele różnic

        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

Najlepsza odpowiedź

0

Twój scenariusz "pierwszego uruchomienia", jak zwykle stanowi jednorazową statycznej inicjalizacji DbContext. To właśnie tutaj DbContext po raz pierwszy wykonuje swoje skojarzenia i będzie realizowana po wykonaniu pierwszego zlecenia. Typowe podejście, które pozwala uniknąć tego dla użytkownika, jest prostym zapytaniu "rozgrzaniu", który jest wykonywany podczas uruchamiania usługi.. na Przykład, po inicjalizacji twojej usługi, wystarczy wpisać coś takiego jak poniżej:

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

To również służy do szybkiego sprawdzenia przy starcie, że baza danych jest dostępna i jest odpowiedzialny. Sam zapytanie wykona bardzo szybką operację, ale w tym czasie DbContext rozwiąże swoje skojarzenia, więc wszelkie nowo utworzone instancje DbContext będą odpowiadać bez żadnych kosztów podczas kwerendy.

Co do surowej wydajności, jeśli oczekuje się, że nie jest to wniosek, który zajmie trochę czasu i połączy prośbę, nie rób tego async. Asynchroniczne żądania nie szybciej, w rzeczywistości są one nieco wolniej. Z pomocą async wnioski do DbContext mają na celu zapewnienie tego, aby twój wątek serwera www / aplikacji reagował podczas przetwarzania potencjalnie kosztownych operacji w bazie danych. Jeśli chcesz uzyskać odpowiedź jak najszybciej, użyj synchroniczny wyzwanie.

Następnie upewnij się, że wszystkie pola, w których można spędzić filtrowania, w tym przypadku Waluta indeksowana. Obecność pola z nazwą Waluty w swojej istocie w postaci ciągu znaków, a nie identyfikator waluty FK (int) wskazanie na rekord waluty już jest dodatkowym wydatkiem na indeksowanie, ponieważ indeksy liczb całkowitych mniej/szybciej, niż indeksy wierszy.

Również nie trzeba się martwić o AsNoTracking podczas korzystania z Count zapytanie. AsNoTracking stosuje się wyłącznie w przypadkach, gdy zwracasz obiekty (ToList/ToArray/Single/Firstitp.) , Aby uniknąć tego, aby DbContext trzymał link do zwrócony istotę. Kiedy używasz Count/Any lub projekcja, aby powrócić właściwości encji za pomocą Select obiekt zwrócony do śledzenia, nie ma.

Należy także pamiętać opóźnienie w sieci między miejscem, w którym wykonywany jest kod twojej aplikacji, a serwerem bazy danych. To jedna i ta sama maszyna lub w grze jest połączenie sieciowe? Jak to się ma podczas wykonywania kwerendy SSMS? Za pomocą programu profiler można zobaczyć, że SQL EF faktycznie wysyła do bazy danych. Wszystko z perspektywy czasu-to koszty: wysyłanie zapytania do bazy danych, Zwrot otrzymanych danych przekaże, analiza tej odpowiedzi. (W przypadku, gdy wracasz do rzeczywistości, wydechu, wypełniasz, сверяете z istniejącymi łączami itp... W przypadku obliczeń itp. weryfikacja istniejących linków)

Wreszcie, aby zapewnić maksymalną wydajność, upewnij się, że czas życia swoich DbContexts zmniejszona. Jeśli DbContext pozostaje otwarta i do niego wykonywał kilka zapytań śledzenia (wybór encji bez AsNoTrackingte śledzone linki na obiekty gromadzą się i mogą negatywnie wpływać na wydajność przyszłych żądań, nawet jeśli używasz AsNoTracking w miarę jak EF sprawdzić, czy śledzisz linki na obiekty, które mogą być stosowane/związane z nowymi żądaniami. Wiele razy widziałem, jak twórcy sugerują, że DbContexts "drogi", więc wolą tworzyć ich jak najmniej, aby uniknąć tych kosztów, tylko po to, aby z czasem zrobić operacji droższe.

Biorąc pod uwagę wszystko to, EF nigdy nie będzie tak szybkie, jak bez leczenia SQL. To ORM, przeznaczony dla zapewnienia wygody .Aplikacje sieciowe, kiedy przychodzi do pracy z danymi. To wygoda w pracy z klasami jednostek, zamiast za każdym razem czyścić i pisać swój własny suchy SQL, wiąże się z określonymi kosztami.

2021-11-23 21:59:24

co do twojego komentarza odnośnie opóźnienia w sieci, jak SSMS, jak i kod sieciowy znajdują się na moim aucie..baza danych znajduje się na serwerze...i do innych rzeczy mam tylko jeden wniosek (jest to POC). W ten sposób, z tym samym opóźnieniem w sieci SSMS może pobierać dane za 40 ms, gdy czysty kod zajmuje 500 ms.....nawet nie próbował z pomocą ADO.CZYSTA, jak wynika z pytania, jedno i drugie mieści się w 500 ms
CrazyMonk

W innych językach

Ta strona jest w innych językach

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