Entity Framework Çok Yavaş. Seçeneklerim neler? [kapalı]


93

"Prematurely Optimize Etme" mantrasını izledim ve Entity Framework kullanarak WCF Hizmetimi kodladım.

Ancak, performansın profilini çıkardım ve Entity Framework çok yavaş. (Uygulamam 2 mesajı yaklaşık 1,2 saniyede işler, burada yeniden yazdığım (eski) uygulama aynı anda 5-6 mesaj gönderir. (Eski uygulama DB Erişimi için sprocs'u çağırır.)

Profil oluşturmam, ileti başına zamanın çoğunu alarak Entity Framework'e işaret ediyor.

Peki seçeneklerim nedir?

  • Orada daha iyi ORM'ler var mı?
    (Sadece nesnelerin normal okunmasını ve yazılmasını destekleyen ve hızlı yapan bir şey ..)

  • Entity Framework'ü daha hızlı yapmanın bir yolu var mı?
    ( Not : Daha hızlı dediğimde, uzun vadede demek istiyorum, ilk arama değil. (İlk arama yavaş (bir mesaj için 15 saniye), ancak bu bir sorun değil. Sadece geri kalanı için hızlı olmasına ihtiyacım var Mesajların.)

  • Hizmetimden daha hızlı çıkmama yardımcı olacak bazı gizemli 3. seçenek.

NOT: DB etkileşimlerimin çoğu Oluştur ve Güncelle. Çok az seçme ve silme yapıyorum.


Bu, 'linq yavaş' yeniden basılması gibi geliyor, EF olduğunu nasıl anlarsınız? Tüm değişikliklerinizin profilini çıkardınız mı?
Maess

6
Cevaplardan bazıları sorulara işaret ediyor. Tecrübelerime göre, EF'deki yavaşlığın sorgularla çok az ilgisi var, bunun yerine gerçekleştirme maliyetleri ile ilgisi var ve bu maliyetler genellikle izlemeyi değiştirmeye ve bunun yaratılan örnekleri nasıl etkilediğine bağlıdır. Ne yazık ki, sizin için sihirli bir değnek yok, bu sadece bir yorum, ancak profil oluşturmanın yüksek gerçekleştirme maliyetlerini ortaya çıkarıp çıkarmadığını ve eğer öyleyse, söz konusu maliyetler hakkında ne yapılabileceğini araştırmanızı tavsiye ederim.
Anthony Pegram

@Maess - Profil oluşturduğumu belirttiğimi ve yavaş olanın EF / DB olduğunu bulduğumu düşündüm. Her iki durumda da, evet yaptım. Bunun profilini çıkardım ve asıl suçlu EF / DB etkileşimleridir.
Vaccano

@Anthony - Maddileştirme ilk önce bir tür şeyler çalıştırmıyor mu? Eğer öyleyse, haklısın, çok yavaş. İlk koşu süper yavaş. Ama belirttiğim gibi, bunun için çok endişelenmiyorum. Sorun, toplam verimdir. (
Maddileştirme

1
@Vaccano, hayır, materyalizasyon, verileri veritabanından alma ve bu verileri temsil etmek için nesnelerin grafiğini örnekleme ve doldurma işlemidir. Kod karıştırıldığı için ilk çalıştırma performansından bahsetmiyorum (hatta Sql Sunucusu sorgu yürütme planını oluşturabilir), ancak nesneler biçiminde her veri aldığınızda ne olur?
Anthony Pegram

Yanıtlar:


46

Entity Framework tarafından gerçekten yayınlanan SQL komutlarının profilini oluşturarak başlamalısınız. Yapılandırmanıza bağlı olarak (POCO, Kendi Kendini İzleme varlıkları) optimizasyonlar için çok yer vardır. ObjectSet<T>.ToTraceString()Yöntemi kullanarak SQL komutlarında hata ayıklayabilirsiniz (hata ayıklama ve yayınlama modu arasında farklılık göstermemelidir) . Daha fazla optimizasyon gerektiren bir sorguyla karşılaşırsanız, EF'e başarmaya çalıştığınız şey hakkında daha fazla bilgi vermek için bazı projeksiyonları kullanabilirsiniz.

Misal:

Product product = db.Products.SingleOrDefault(p => p.Id == 10);
// executes SELECT * FROM Products WHERE Id = 10

ProductDto dto = new ProductDto();
foreach (Category category in product.Categories)
// executes SELECT * FROM Categories WHERE ProductId = 10
{
    dto.Categories.Add(new CategoryDto { Name = category.Name });
}

Şununla değiştirilebilir:

var query = from p in db.Products
            where p.Id == 10
            select new
            {
                p.Name,
                Categories = from c in p.Categories select c.Name
            };
ProductDto dto = new ProductDto();
foreach (var categoryName in query.Single().Categories)
// Executes SELECT p.Id, c.Name FROM Products as p, Categories as c WHERE p.Id = 10 AND p.Id = c.ProductId
{
    dto.Categories.Add(new CategoryDto { Name = categoryName });
}

Bunu kafamdan yazdım, bu tam olarak nasıl yürütüleceği değil, ancak EF aslında sorgu hakkında bildiğiniz her şeyi söylerseniz bazı güzel optimizasyonlar yapıyor (bu durumda, kategoriye ihtiyacımız olacak - isimler). Ancak bu, istekli yükleme (db.Products.Include ("Kategoriler")) gibi değildir, çünkü projeksiyonlar yüklenecek veri miktarını daha da azaltabilir.


40
Bu yanıt, anonim türlerin tanımlandıkları yöntemin dışında erişilebilir olmadığını anlayana kadar mantıklı geliyor. Karmaşık bir nesneyi yüklemek ve bir megamot yazmak istemiyorsanız, yeni anonim türlerinizi bir tür POCO'ya dönüştürmeniz gerekir. Yine, bunu yaparken KENDİ KURULUŞ ÇERÇEVENİZİ YENİDEN YAZDIRDIĞINIZIN farkına varana kadar kulağa mantıklı geliyor. Hangi saçmalık.
Doug

5
bu benim için hızda 15x-20x artışla sonuçlandı.
Dave Cousineau

12
İlginç ve faydalı cevap, bir süre sonra hala geçerli. @Doug: Ekstra faydayı gerçekten kullanmanız gereken birkaç sorguyu yalnızca optimize ettiğiniz (projeksiyonları kullanarak) olduğundan bu gerçekten saçma değil. EF ve POCO size makul bir varsayılan değer verir, bu çok güzel!
Victor

2
@Doug Çoğu uygulamanın salt görüntülenebilir senaryolar için görüntüleme modelleri vardır, değil mi? Verileri çıkardığınız kadar eşleme de yapabilirsiniz.
Casey

4
ORM'lerin gelecek olduğunu düşünürdüm. Ben onları kullanmaya başlayana kadar mantıklıydılar. Sonra Dapper'ı buldum . Şimdi, bunun gibi çözümler gördüğümde, karmaşıklığın nasıl hızla arttığını görüyorum. C # ile soyutlanmış SQL yazmak hayatın içinden geçmenin yolu değildir.
Michael Silver

81

Gerçek şu ki, Entity Framework gibi ürünler HER ZAMAN yavaş ve verimsiz olacak çünkü çok daha fazla kod çalıştırıyorlar.

Ayrıca insanların LINQ sorgularını optimize etmeleri, oluşturulan SQL'e bakmaları, hata ayıklayıcıları kullanmaları, ön derleme yapmaları, fazladan birçok adım atmaları vb. Yani çok fazla zaman kaybetmeleri gerektiğini önermelerini aptalca buluyorum. Kimse - Basitleştirin! Herkes daha fazla adım atarak (zaman kaybetmek) işleri karmaşıklaştırmak ister.

Sağduyulu bir yaklaşım, EF veya LINQ kullanmamak olacaktır. Düz SQL kullanın. Bunda yanlış bir şey yok. Programcılar arasında sürü zihniyeti olması ve piyasadaki her yeni ürünü kullanma dürtüsü hissetmeleri, bunun iyi olduğu ya da işe yarayacağı anlamına gelmez. Çoğu programcı, büyük bir şirket tarafından yayınlanan her yeni kod parçasını dahil ederse, bunun kendilerini daha akıllı bir programcı yaptığını düşünüyor; hiç doğru değil. Akıllı programlama çoğunlukla daha az baş ağrısı, belirsizlik ve en kısa sürede daha fazlasını nasıl yapacağımızla ilgilidir. Zamanı hatırla! Bu en önemli unsurdur, bu yüzden basitçe bazı garip sözde 'kalıplara' uymak için yazılmış kötü / şişirilmiş koddaki problemleri çözmek için boşa harcamamanın yollarını bulmaya çalışın.

Rahatlayın, hayatın tadını çıkarın, kodlamaya ara verin ve ekstra özellikler, kodlar, ürünler, 'desenler' kullanmayı bırakın. Hayat kısa ve kodunuzun ömrü daha da kısadır ve kesinlikle roket bilimi değildir. LINQ, EF ve diğerleri gibi katmanları kaldırın ve kodunuz verimli bir şekilde çalışacak, ölçeklenecek ve evet, bakımı yine de kolay olacak. Çok fazla soyutlama kötü bir "kalıp" tır.

Ve sorununun çözümü budur.


157
Bu, bebeği banyo suyuyla dışarı atmaktır. Darboğazları optimize edersiniz, birkaç yerde çok yavaş, diğerlerinde ise çok hızlı olduğu için EF'yi atmak aptalca olur. Neden ikisini birden kullanmıyorsunuz? EF, saklı yordamları ve ham SQL'i gayet iyi işler. 10+ saniye süren bir LINQ-SQL sorgusunu ~ 1 saniye süren bir SP'ye dönüştürdüm, ancak tüm LINQ'dan SQL'e atmayacağım. Diğer basit durumlarda, daha az kod ve hata için daha az yer ile ÇOK zaman tasarrufu sağladı ve sorgular derleyici doğrulanır ve veritabanıyla eşleşir. Daha az kod, daha kolay bakım ve daha az hata alanı demektir.
JulianR

12
Genel olarak tavsiyeniz iyidir, ancak zamanın% 10'unda iyi çalışmadıkları için EF veya diğer soyutlamaları terk etmenin doğru olduğunu düşünmüyorum.
JulianR

50
Düz SQL = bakımı kolay mı? Pek çok iş mantığına sahip çok büyük uygulamalar için doğru değil. Karmaşık, yeniden kullanılabilir SQL yazmak, yapmak kolay bir şey değildir. Kişisel olarak EF ile bazı performans sorunlarım oldu, ancak bu sorunlar RAD ve işleri KURU olarak tutma (ilgili herhangi bir karmaşıklık düzeyi varsa) açısından uygun bir ORM'nin faydalarıyla karşılaştırılamaz.
MemeDeveloper

13
+ 10 ^ 100 Çok fazla soyutlama kötü bir 'kalıp'
Makach

59
-1. "EF HER ZAMAN yavaş ve verimsiz olacaktır." Neden böyle bir şeyin mutlak gerçek olduğunu iddia ettiğini anlamıyorum. Daha fazla katmana sahip olmak bir şeyi daha yavaş hale getirecektir, ancak bu farkın bile BİLDİRİLEBİLİR olup olmadığı tamamen veri miktarı ve yürütülen sorgunun türü gibi duruma bağlıdır. Bana göre bu, 'C # HER ZAMAN yavaş ve verimsiz olacak' demekle aynı şey çünkü C ++ 'dan daha yüksek bir soyutlamadır. Yine de birçok kişi bunu kullanmayı tercih ediyor çünkü verimlilik artışı, performans kaybının çok ötesinde oluyor (eğer varsa). Aynısı EF
Despertar

37

Bir öneri, LINQ to Entity Framework'ü yalnızca tek kayıtlı CRUD ifadeleri için kullanmaktır.

Daha fazla ilgili sorgular, aramalar, raporlama vb. İçin bir saklı yordam yazın ve bunu MSDN'de açıklandığı gibi Entity Framework modeline ekleyin .

Birkaç sitemde benimsediğim yaklaşım bu ve verimlilik ile performans arasında iyi bir uzlaşma gibi görünüyor. Entity Framework, eldeki görev için her zaman en verimli SQL'i oluşturmayacaktır. Ve nedenini anlamak için zaman harcamaktansa, daha karmaşık sorgular için saklı yordam yazmak aslında bana zaman kazandırıyor. Sürece aşina olduğunuzda, depolanan işlemleri EF modelinize eklemek çok da zor olmaz. Ve tabii ki onu modelinize eklemenin yararı, bir ORM kullanmaktan gelen güçlü bir şekilde yazılmış iyiliği elde etmenizdir.


Db.athlete.find (id) gibi yapı iskelelerinde kullanılan yöntemler hakkında bir fikriniz var mı? ADO.NET veya dapper ile karşılaştırıldığında nasıl performans gösteriyorlar?
bir tuzak

15

Eğer ediyorsanız tamamen veriler alınırken, bu bunu getirir varlıkları takip değil EF anlatmak performansına büyük yardım bu. Bunu MergeOption.NoTracking kullanarak yapın. EF yalnızca sorguyu oluşturur, yürütür ve sonuçları nesnelere kaldırır, ancak varlık değişikliklerini veya bu nitelikteki herhangi bir şeyi izlemeye çalışmaz. Bir sorgu basitse (veritabanının geri dönmesini beklerken fazla zaman harcamıyorsa), NoTracking olarak ayarlamanın sorgu performansını iki katına çıkarabileceğini buldum.

MergeOption numaralandırmasıyla ilgili şu MSDN makalesine bakın:

Kimlik Çözümü, Durum Yönetimi ve Değişiklik Takibi

Bu, EF performansı hakkında iyi bir makale gibi görünüyor:

Performans ve Entity Framework


9
Herhangi biri bunu yapmadan önce burada okumak iyi bir fikir olabilir. stackoverflow.com/questions/9259480/…
leen3o

6

Uygulamanın profilini çıkardığını söylüyorsun. ORM'nin profilini de çıkardınız mı? Ayende'den EF kodunuzu nerede optimize edebileceğinizi vurgulayan bir EF profilcisi vardır. Burada bulabilirsiniz:

http://efprof.com/

Performans elde etmeniz gerekiyorsa, ORM'nizin yanında geleneksel bir SQL yaklaşımını kullanabileceğinizi unutmayın.

Daha hızlı / daha iyi bir ORM varsa? Nesne / veri modelinize bağlı olarak, Dapper , Massive veya PetaPoco gibi mikro ORM'lerden birini kullanmayı düşünebilirsiniz .

Dapper sitesi, size diğer ORM'lerle nasıl karşılaştırıldıklarına dair bir fikir verecek bazı karşılaştırmalı karşılaştırmalar yayınlar. Ancak mikro ORM'lerin EF ve NH gibi tam ORM'lerin zengin özellik kümesini desteklemediğini belirtmek gerekir.

RavenDB'ye bir göz atmak isteyebilirsiniz . Bu, POCO'ları eşleştirme gerekmeden doğrudan depolamanıza olanak tanıyan ilişkisel olmayan bir veritabanıdır (yine Ayende'den) . RavenDB, okumalar için optimize edilmiştir ve şemayı değiştirme ve nesnelerinizi bu şemayla eşleme ihtiyacını ortadan kaldırarak geliştiricilerin hayatını çok daha kolaylaştırır. Bununla birlikte, bunun ORM yaklaşımını kullanmak için önemli ölçüde farklı bir yaklaşım olduğunu ve bunların ürünün sitesinde ana hatlarıyla açıklandığını unutmayın .


4

@Slauma'nın cevabını burada işleri hızlandırmak için çok yararlı buldum . Hem ekler hem de güncellemeler için aynı türden bir model kullandım ve performans roketlendi.


2

Tecrübelerime göre, sorun EF ile değil, ORM ile ilgili.

Genel olarak tüm ORM'ler, optimize edilmemiş sorgular vb. N + 1 sorunundan muzdariptir . En iyi tahminim, performans düşüşüne neden olan sorguları izlemek ve ORM aracını ayarlamaya çalışmak veya bu parçaları SPROC ile yeniden yazmak olacaktır.


2
İnsanlar bana bunu söyleyip duruyor. Ancak, eski usul ADO'yu kullanarak basit bir seçme ifadesi oluşturacağım ve bir EF bağlamı kullanarak aynı basit seçim ve EF her zaman önemli ölçüde daha yavaştır. EF'i gerçekten sevmek istiyorum, ancak hayatı kolaylaştırmak yerine zorlaştırmaya devam ediyor.
Sinaesthetic

1
@Sinaesthetic Tabii ki daha yavaş. Aynı belirteçle, Linq to Objects kullanılarak yazılan kod genellikle onsuz yazılan koddan daha yavaştır. Asıl soru gerçekten daha hızlı mı yoksa hızlı mı olduğu değil (nasıl olabilir, kaputun altındayken el ile yaptığınız sorguyu hala yayınlaması gerekiyor mu?) Ama 1) ihtiyaçlarınız için hala yeterince hızlı 2) kaydeder kodu yazarken 3) faydalar maliyetleri telafi eder. Bu öğelere dayanarak EF'in birçok proje için uygun olduğunu düşünüyorum.
Casey

@Sinaesthetic Ayrıca, bir ORM kullanmazsanız, her SQL sorgusunun ince ayarlı ve optimize edilmiş olması değil, uygulamanın kurum içi, organik, kötü -Desteklenen, düşük performanslı ORM, ekibiniz olağanüstü disiplinli değilse ve performans konusunda çok endişeli değilse.
Casey


1

Ben de bu konuyla karşılaştım. EF'yi terk etmekten nefret ediyorum çünkü çok iyi çalışıyor, ama sadece yavaş. Çoğu durumda sadece bir kayıt bulmak veya güncellemek / eklemek istiyorum. Bunun gibi basit işlemler bile yavaştır. Bir tablodan 1100 kaydı Listeye geri çektim ve bu işlem EF ile 6 saniye sürdü. Benim için bu çok uzun, kurtarmak bile çok uzun sürüyor.

Kendi ORM'mi oluşturmaya başladım. Aynı 1100 kaydı bir veritabanından aldım ve ORM'm EF'den çok daha hızlı 2 saniye sürdü. ORM ile her şey neredeyse anında. Şu anda tek sınırlama, yalnızca MS SQL Server ile çalışması, ancak Oracle gibi başkalarıyla çalışmak üzere değiştirilebilir olmasıdır. Şu anda her şey için MS SQL Server kullanıyorum.

ORM'mi denemek isterseniz işte bağlantı ve web sitesi:

https://github.com/jdemeuse1204/OR-M verileri-Entities

Veya nugget kullanmak istiyorsanız:

PM> Yükleme Paketi OR-M_DataEntities

Belgeler de orada


0

Yalnızca profil oluşturduktan sonra optimize etmek mantıklıdır. DB erişiminin yavaş olduğunu öğrenirseniz, saklı yordamları kullanmaya dönüşebilir ve EF'yi koruyabilirsiniz. EF'nin yavaş olduğunu anlarsanız, farklı bir ORM'ye geçmeniz veya bir ORM kullanmamanız gerekebilir.


0

Saniyede 120 İstek gerçekleştiren benzer bir uygulamaya (Wcf -> EF -> veritabanı) sahibiz, bu yüzden EF'nin burada sizin sorununuz olmadığından eminim, derlenmiş sorgularda önemli performans iyileştirmeleri gördüm.


Kodumun% 98'i Çağrıları Oluştur ve Güncelle. Bunun bir fark yaratır mı bilmiyorum ama saniyede 120'den çok daha yavaş.
Vaccano

evet bu tipik bir uygulama olmaz, başvurunuzun profilini çıkarmanızı öneririm. bizim için çoğunlukla okunuyor ...
np-hard

0

EF, LINQ to SQL ve zarif kullandım. Dapper en hızlısıdır. Örnek: Her biri 4 alt kayıt içeren 1000 ana kayda ihtiyacım vardı. LINQ'dan sql'yi kullandım, yaklaşık 6 saniye sürdü. Daha sonra dapper'a geçtim, depolanan tek prosedürden 2 kayıt seti aldım ve her kayıt için alt kayıtları ekledim. Toplam süre 1 saniye.

Ayrıca saklı yordam çapraz uygulama ile tablo değeri işlevlerini kullandı, skaler değer işlevlerinin çok yavaş olduğunu buldum.

Benim tavsiyem, EF veya LINQ to SQL kullanmak ve belirli durumlar için zarif bir moda geçmek olacaktır.


-1

Entity Framework, büyük darboğazlara neden olmamalıdır. Muhtemelen başka sebepler de vardır. EF'yi Linq2SQL'e geçirmeyi deneyebilirsiniz, her ikisinin de karşılaştırma özellikleri vardır ve kodun dönüştürülmesi kolay olmalıdır, ancak çoğu durumda Linq2SQL EF'den daha hızlıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.