EF 4.1'e varlıkları eklemek ObjectContext'e kıyasla neden bu kadar yavaş?


81

Temel olarak, bir işleme 35000 nesne ekliyorum:

using(var uow = new MyContext()){
  for(int i = 1; i < 35000; i++) {
     var o = new MyObject()...;
     uow.MySet.Add(o);
  }
  uow.SaveChanges();
}

Bu sonsuza kadar sürer! Temel ObjectContext'yi kullanırsam (kullanarak IObjectAdapter), yine de yavaştır ancak yaklaşık 20 saniye sürer. Görünüşe göre DbSet<>, kare miktarda zaman alan bazı doğrusal aramalar yapıyor ...

Bu sorunu gören başka kimse var mı?


3
Bir şekilde cevabın
şuna

Yanıtlar:


128

Yorumda Ladislav tarafından daha önce belirtildiği gibi, performansı iyileştirmek için otomatik değişiklik algılamayı devre dışı bırakmanız gerekir:

context.Configuration.AutoDetectChangesEnabled = false;

Bu değişiklik algılama, DbContextAPI'de varsayılan olarak etkindir .

API'den DbContextbu kadar farklı davranmasının nedeni , otomatik değişiklik algılama etkinleştirildiğinde API'nin ObjectContextbirçok işlevinin DbContextAPI işlevlerinden daha DetectChangesdahili olarak çağırmasıdır ObjectContext.

BuradaDetectChanges varsayılan olarak çağıran işlevlerin bir listesini bulabilirsiniz . Onlar:

  • Add, Attach, Find, Local, Veya Removeüyeler üzerindeDbSet
  • GetValidationErrors, EntryVeya SaveChangesüyeler üzerindeDbContext
  • EntriesyöntemDbChangeTracker

Özellikle yaşadığınız düşük performanstan sorumlu olan Addaramalar DetectChanges.

Bunun aksine, ObjectContextAPI DetectChangesyalnızca otomatik olarak gelir, SaveChangesancak içeride değil AddObjectve yukarıda belirtilen diğer ilgili yöntemler. Varsayılan performansının ObjectContextdaha hızlı olmasının nedeni budur .

Neden bu DbContextkadar çok işlevde bu varsayılan otomatik değişiklik algılamayı tanıttılar ? Emin değilim, ancak görünüşe göre onu devre dışı bırakmak ve DetectChangesuygun noktalarda manuel olarak aramak gelişmiş olarak kabul ediliyor ve uygulamanıza kolayca ince hatalar ekleyebileceği için [it] 'i dikkatli kullanın .


@Ladislav: Haklısın Bunu sadece ek sorunları aradığım için bulamadım :-(
Hartmut

Açıklama için teşekkürler. Aslında context.Configuration.AutoDetectChangesEnabled = false çağırıyordum ancak Seed () yönteminde veritabanı oluşturma sırasında yaptım. Bunun varsayılanı belirleyeceğini düşündüm. Her seferinde onu aramam gerektiğinin farkında değildim. Teşekkürler!
Hartmut

3
@Hartmut: Türetilmiş DbContext'inizin yapıcısının içindeki değişiklik algılamasını devre dışı bırakabilir, ardından her zaman devre dışı bırakabilirsiniz. Ama kişisel olarak, devre dışı bırakıldığında "potansiyel olarak ince böceklerin ortaya çıkması" hakkındaki bu sözler beni endişelendiriyor. Varsayılan olarak değişiklik algılamasını açtım ve bunu yalnızca sizinki gibi performans artışının açık olduğu ve sorun yaratmayacağına dair kendimi güvende hissettiğim kod bloklarında devre dışı bıraktım.
Slauma

Kabul ediyorum, uygulamamın yalnızca performans açısından kritik bir bölümünü test ediyordum. Üretim kodunda, bunu toplu ekler vb. Durumlarla sınırlamak en iyisidir
Hartmut

Bu cevap için teşekkür ederim. Dışarıda çok fazla bilgi var, ancak bu sizi takip etmeyi bırakıyor!
Fred Wilson

12

EF 4.3 CodeFirst ile küçük deneysel test:

AutoDetectChanges ile kaldırılan 1000 nesne = true: 23 sn

AutoDetectChanges ile kaldırılan 1000 nesne = false: 11 sn

AutoDetectChanges ile 1000 nesne eklendi = true: 21 sn

AutoDetectChanges ile 1000 nesne eklendi = false: 13 sn


1
Teşekkürler Zax. Soruya göre 35.000 ile sonuçlarınız nedir? Orijinal soruda performansın ikinci dereceden düştüğünü göreceksiniz
Daniel Dyson

9

.Netcore 2.0'da bu şu adrese taşındı:

context.ChangeTracker.AutoDetectChangesEnabled = false;


1

Burada bulduğunuz cevapların yanı sıra. Veritabanı düzeyinde eklemenin eklemekten daha fazla iş olduğunu bilmek önemlidir. Veritabanının yeni alanı genişletmesi / tahsis etmesi gerekir. Daha sonra en azından birincil anahtar dizinini güncellemesi gerekir. Güncelleme sırasında indeksler de güncellenebilse de, çok daha az yaygındır. Herhangi bir yabancı anahtar varsa, bilgi tutarlılığının korunduğundan emin olmak için bu dizinleri de okuması gerekir. Tetikleyiciler, güncellemeleri aynı şekilde etkileyebilse de bir rol oynayabilir.

Tüm bu veritabanı çalışması, kullanıcı girişlerinden kaynaklanan günlük giriş etkinliğinde anlamlıdır. Ancak, yalnızca mevcut bir veritabanını yüklüyorsanız veya çok fazla ek oluşturan bir işleminiz varsa. Sonuna kadar erteleyerek bunu hızlandırmanın yollarına bakmak isteyebilirsiniz. Normalde eklerken dizinleri devre dışı bırakmak yaygın bir yoldur. Vakaya bağlı olarak yapılabilecek çok karmaşık optimizasyonlar vardır, biraz bunaltıcı olabilirler.

Sadece genel olarak eklemenin güncellemelerden daha uzun süreceğini bilin.

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.