Entity Framework Arıthabort AÇIK, ancak yine de sorgu yavaş

0

Soru

Basit bir sorgum var

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

Tabloda yalnızca 3 Sütun ve 10 satır veri vardır.

Sorguyu Net 5 projesinden yürütmeye çalıştığımda, ilk kez yaklaşık 2.3 saniye ve sonraki istekler için 500ms (+- 100) sürüyor. Aynı isteği ssms'de vurduğumda neredeyse hiç zaman kaybetmeden geri dönüyor (sql profiler'da görüldüğü gibi 45ms).

Buradan ef'de ARİTHABORT'U uyguladım

SQL Profiler'da gördüğümde ARITHABORT'U açık olarak ayarlıyor ancak yine de sorgu ilk istek ve sonraki istekler için aynı süreyi alıyor.

sql profiler screen shot

SSMS sorgu hızıyla aynı hıza nasıl ulaşabilirim. Projemin yanıtı 1 saniyede geri getirme gereksinimi olduğu için sorgunun gerçekten hızlı çalışmasına ihtiyacım var (En az 5 basit DB çağrısı yapmam gerekiyor...1 çağrı 500 ms sürerse, 1 saniyelik gereksinimi aşıyor demektir)

Düzenlemek

Hatta denendi ADO.Net SQL Profiler'da görüldüğü gibi geçen yürütme süresi 40 ms'dir, koda ulaştığında olduğu gibi neredeyse 400 ms'dir. Çok fazla fark

        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

En iyi cevabı

0

"İlk çalıştırma" senaryonuz genellikle dbcontext'in tek seferlik statik başlatılmasıdır. DbContext eşlemelerini ilk kez çalıştığı ve ilk sorgu yürütüldüğünde ortaya çıkacağı yer burasıdır. Bunun bir kullanıcı için oluşmasını önlemek için tipik yaklaşım, hizmet başlatıldığında çalışan basit bir "ısınma" sorgusuna sahip olmaktır.. Örneğin, hizmetiniz başlatıldıktan sonra, aşağıdaki gibi bir şey koymanız yeterlidir:

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

Bu aynı zamanda veritabanının erişilebilir olduğunu ve yanıt verdiğini hızlı bir başlangıç denetimi olarak da işlev görür. Sorgunun kendisi çok hızlı bir işlem yapar, ancak DbContext eşlemelerini şu anda çözer, böylece yeni oluşturulan DbContext örnekleri istek sırasında bu maliyete maruz kalmadan yanıt verir.

Ham performansa gelince, biraz zaman alması ve bir isteği bağlaması beklenen bir sorgu değilse, bunu yapmayın async. Eşzamansız istekler daha hızlı değildir, aslında biraz daha yavaştır. Kullanım async dbcontext'e yönelik istekler, web sunucunuzun / uygulama iş parçacığınızın potansiyel olarak pahalı veritabanı işlemleri işlenirken yanıt vermesini sağlamakla ilgilidir. Mümkün olduğunca çabuk yanıt almak istiyorsanız, senkronize bir arama kullanın.

Ardından, filtrelediğiniz alanların, bu durumda Para Biriminin endekslendiğinden emin olun. Varlığınızda CurrencyId FK yerine bir Dize olarak Currency adlı bir alana sahip olmak (int) bir Para Birimi kaydına işaret etmek, tamsayılardaki dizinler dizelerdekilerden daha küçük/daha hızlı olduğu için zaten fazladan bir indeksleme masrafıdır.

Ayrıca uğraşmanıza gerek yok AsNoTracking bir kullanırken Count sorgu. AsNoTracking yalnızca varlıkları iade ettiğinizde geçerlidir (ToList/ToArray/Single/Firstvb.) dbcontext'in döndürülen varlığa bir başvuru tutmasını önlemek için. Kullandığınızda Count/Any veya kullanarak varlıklardan özellikleri döndürmek için projeksiyon Select izlemek için döndürülen bir varlık yok.

Ayrıca, uygulama kodunuzun çalıştığı yer ile veritabanı sunucusu arasındaki ağ gecikmesini de göz önünde bulundurun. Aynı makine mi yoksa oyunda bir ağ bağlantısı var mı? Bir SSMS sorgusu gerçekleştirirken bu nasıl karşılaştırılır? Bir profil oluşturucu kullanarak, SQL ef'nin veritabanına gerçekte ne gönderdiğini görebilirsiniz. Zaman açısından diğer her şey bir maliyettir: İsteği dB'ye almak, Elde edilen verileri istek sahibine geri almak, bu yanıtı ayrıştırmak. (Varlıkları döndürdüğünüz, ayırdığınız, doldurduğunuz, mevcut referanslara karşı kontrol ettiğiniz vb. Durumlarda... Sayım vb. Durumlarda. mevcut referansları kontrol etme)

Son olarak, en yüksek performansı elde ettiğinizden emin olmak için DbContexts ömrünüzün kısa tutulduğundan emin olun. Bir DbContext açık tutulursa ve ın'ye karşı bir dizi izleme sorgusu çalıştırılmışsa (Olmayan varlıkları seçme AsNoTracking) izlenen varlık başvuruları birikir ve kullansanız bile gelecekteki sorgular üzerinde olumsuz bir performans etkisi yaratabilir AsNoTracking EF, yeni sorgularınızla ilgili/ilgili olabilecek varlıklar için izlenen referansları kontrol etmeye çalıştığı için. Çoğu zaman geliştiricilerin dbcontext'lerin "pahalı" olduğunu varsaydıklarını görüyorum, bu nedenle bu maliyetlerden kaçınmak için mümkün olduğunca az örneklemeyi tercih ediyorlar, ancak zaman içinde işlemleri daha pahalı hale getiriyorlar.

Tüm bunlar göz önüne alındığında, EF asla ham SQL kadar hızlı olmayacaktır. Verilerle çalışmak söz konusu olduğunda.Net uygulamalarına kolaylık sağlamak için tasarlanmış bir orm'dir. Her seferinde kendi ham sql'inizi sterilize etmek ve yazmak yerine varlık sınıflarıyla çalışmadaki bu kolaylık bir maliyetle birlikte gelir.

2021-11-23 21:59:24

ağ gecikmesi ile ilgili yorumunuza gelince, hem SSMS hem de Net Kodu makinemde..db sunucuda...ve diğer şeyler için sadece bir sorgum var (bu bir POC). Bu nedenle, aynı ağ gecikmesiyle SSMS, Net Kodun 500ms aldığı 40ms'de getirebilir.....hatta denedim ADO.NET soruda görüldüğü gibi, her ikisi de 500ms alıyor
CrazyMonk

Diğer dillerde

Bu sayfa diğer dillerde

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