Performans için Modelleme

Çoğu durumda, modelleme yönteminizin uygulamanızın performansı üzerinde derin bir etkisi olabilir; düzgün normalleştirilmiş ve "doğru" bir model genellikle iyi bir başlangıç noktası olsa da, gerçek dünyadaki uygulamalarda bazı pragmatik tavizler iyi performans elde etmek için uzun bir yol kat edebilir. Bir uygulama üretimde çalıştırıldıktan sonra modelinizi değiştirmek oldukça zor olduğundan, ilk modeli oluştururken performansı göz önünde bulundurmaya değer.

Normalleştirme ve önbelleğe alma

Normal dışıleştirme , genellikle sorgu sırasında birleştirmeleri ortadan kaldırmak için şemanıza yedekli veriler ekleme uygulamasıdır. Örneğin, her Gönderinin Derecelendirmesi olan Bloglar ve Gönderiler içeren bir model için blogun ortalama derecelendirmesini sık sık göstermeniz gerekebilir. Bu basit yaklaşım Gönderileri Bloglarına göre gruplandırıp sorgunun bir parçası olarak ortalamayı hesaplar; ancak bu, iki tablo arasında maliyetli bir birleştirme gerektirir. Normal dışı bırakma, tüm gönderilerin hesaplanmış ortalamasını Blog'daki yeni bir sütuna ekler, böylece ekleme veya hesaplama yapmadan hemen erişilebilir duruma gelir.

Yukarıdakiler bir önbelleğe alma biçimi olarak görüntülenebilir. Gönderiler'den toplanan bilgiler Bloglarında önbelleğe alınır ve herhangi bir önbelleğe almada olduğu gibi, sorun önbelleğe alınan değerin önbelleğe alınan verilerle nasıl güncel tutulacağıdır. Çoğu durumda, önbelleğe alınan verilerin bir süre gecikmesi sorun olmaz; örneğin, yukarıdaki örnekte blog'un ortalama derecelendirmesinin herhangi bir noktada tamamen güncel olmaması genellikle mantıklıdır. Böyle bir durum söz konusuysa, arada bir yeniden hesaplayabilirsiniz; aksi takdirde, önbelleğe alınan değerleri güncel tutmak için daha ayrıntılı bir sistem ayarlanmalıdır.

Aşağıda EF Core'da normal dışı ve önbelleğe alma ile ilgili bazı teknikler ayrıntılı olarak açıklanmıştır ve belgelerde ilgili bölümlere işaret eder.

Depolanan hesaplanan sütunlar

Önbelleğe alınacak veriler aynı tablodaki diğer sütunların ürünüyse, depolanan hesaplanan sütun mükemmel bir çözüm olabilir. Örneğin, ve Customer sütunları olabilir FirstNameLastName , ancak müşterinin tam adına göre arama yapmamız gerekebilir. Depolanan bir hesaplanan sütun, veritabanı tarafından otomatik olarak korunur ve bu sütun satır her değiştirildiğinde yeniden hesaplanır ve hatta sorguları hızlandırmak için bunun üzerinde bir dizin tanımlayabilirsiniz.

Girişler değiştiğinde önbellek sütunlarını güncelleştirme

Önbelleğe alınan sütununuzun tablonun satırının dışındaki girişlere başvurması gerekiyorsa, hesaplanan sütunları kullanamazsınız. Ancak, girişi her değiştiğinde sütunu yeniden hesaplamak mümkündür; örneğin, bir Gönderi her değiştirildiğinde, eklendiğinde veya kaldırıldığında ortalama Blog derecelendirmesini yeniden hesaplayabilirsiniz. Yeniden hesaplama gerektiğinde tam koşulları tanımladığınızdan emin olun, aksi takdirde önbelleğe alınan değeriniz eşitlenmez.

Bunu gerçekleştirmenin bir yolu, güncelleştirmeyi normal EF Core API'sini kullanarak kendiniz gerçekleştirmektir. SaveChangesOlaylar veya kesme noktaları , herhangi bir Gönderinin güncelleştirilip güncelleştirilmediğini otomatik olarak denetlemek ve yeniden hesaplamayı bu şekilde gerçekleştirmek için kullanılabilir. Ek komutların gönderilmesi gerektiğinden bunun genellikle ek veritabanı gidiş dönüşlerini gerektirdiğini unutmayın.

Performansa duyarlı daha fazla uygulama için, veritabanında yeniden hesaplamayı otomatik olarak gerçekleştirmek için veritabanı tetikleyicileri tanımlanabilir. Bu, ek veritabanı gidiş dönüşlerini kaydeder, ana güncelleştirmeyle aynı işlem içinde otomatik olarak gerçekleşir ve ayarlanması daha kolay olabilir. EF tetikleyicileri oluşturmak veya korumak için belirli bir API sağlamaz, ancak boş bir geçiş oluşturmak ve tetikleyici tanımını ham SQL aracılığıyla eklemek son derece uygundur.

Gerçekleştirilmiş/dizinlenmiş görünümler

Gerçekleştirilmiş (veya dizine alınan) görünümler normal görünümlere benzer, ancak bu görünümlerin verileri her sorgulandığında hesaplanmak yerine diskte ("gerçekleştirilmiş") depolanır. Bu tür görünümler, pahalı olabilecek hesaplamaların sonuçlarını önbelleğe aldıklarından, kavramsal olarak depolanan hesaplanan sütunlara benzer; ancak tek bir sütun yerine sorgunun sonuç kümesinin tamamını önbelleğe alır. Gerçekleştirilmiş görünümler her normal tablo gibi sorgulanabilir ve diskte önbelleğe alındıklarından, bu tür sorgular görünümü tanımlayan sorgunun pahalı hesaplamalarını sürekli yapmak zorunda kalmadan çok hızlı ve ucuz bir şekilde yürütülür.

Gerçekleştirilmiş görünümler için belirli destek veritabanları arasında farklılık gösterir. Bazı veritabanlarında (örneğin PostgreSQL), gerçekleştirilmiş görünümlerin değerlerinin temel tablolarıyla eşitlenebilmesi için el ile yenilenmesi gerekir. Bu genellikle bir süreölçer aracılığıyla (bazı veri gecikmelerinin kabul edilebilir olduğu durumlarda) veya belirli koşullarda tetikleyici veya saklı yordam çağrısı yoluyla yapılır. Sql Server Dizinli Görünümler ise temel tabloları değiştirildiğinde otomatik olarak güncelleştirilir; bu, görünümün her zaman daha yavaş güncelleştirmeler karşılığında en son verileri göstermesini sağlar. Buna ek olarak, SQL Server Dizin Görünümleri'nin destekledikleri konusunda çeşitli kısıtlamaları vardır; daha fazla bilgi için belgelere bakın.

EF şu anda görünümleri oluşturmak veya korumak için, gerçekleştirilmiş/dizinlenmiş veya başka bir şekilde belirli bir API sağlamaz; ancak boş bir geçiş oluşturmak ve ham SQL aracılığıyla görünüm tanımını eklemek son derece uygundur.

Devralma eşlemesi

Bu bölüme devam etmeden önce devralmayla ilgili ayrılmış sayfanın okunmasını öneririz.

EF Core şu anda bir devralma modelini ilişkisel veritabanına eşlemek için üç tekniği desteklemektedir:

  • Tüm .NET sınıf hiyerarşisinin tek bir veritabanı tablosuna eşlendiği hiyerarşi başına tablo (TPH).
  • .NET hiyerarşisindeki her türün veritabanındaki farklı bir tabloya eşlendiği tür başına tablo (TPT).
  • .NET hiyerarşisindeki her somut türün veritabanındaki farklı bir tabloya eşlendiği ve her tablonun karşılık gelen türün tüm özellikleri için sütunlar içerdiği beton başına tablo türü (TPC).

Devralma eşleme tekniğinin seçimi, uygulama performansı üzerinde önemli bir etkiye sahip olabilir. Bir seçim gerçekleştirmeden önce dikkatli bir şekilde ölçülebilir.

Sezgisel olarak, TPT "daha temiz" bir teknik gibi görünebilir; her .NET türü için ayrı bir tablo, veritabanı şemasının .NET tür hiyerarşisine benzer görünmesini sağlar. Buna ek olarak, TPH tek bir tablodaki hiyerarşinin tamamını temsil etmesi gerektiğinden, satırlar satırda tutulan türden bağımsız olarak tüm sütunlara sahiptir ve ilişkisiz sütunlar her zaman boş ve kullanılmamış olur. "Belirsiz" bir eşleme tekniği gibi görünmenin yanı sıra, çoğu kişi bu boş sütunların veritabanında önemli bir yer kapladığına ve performansı da incitebileceğine inanıyor.

Bahşiş

Veritabanı sisteminiz destekliyorsa (örneğin SQL Server), nadiren doldurulacak TPH sütunları için "seyrek sütunlar" kullanmayı göz önünde bulundurun.

Ancak ölçüm, TPT'nin çoğu durumda performans açısından alt eşleme tekniği olduğunu gösterir; TPH'deki tüm verilerin tek bir tablodan geldiği durumlarda, TPT sorgularının birden çok tabloyu birleştirmesi gerekir ve birleşimler ilişkisel veritabanlarında performans sorunlarının birincil kaynaklarından biridir. Veritabanları genellikle boş sütunlarla da ilgilenme eğilimindedir ve SQL Server seyrek sütunları gibi özellikler bu ek yükü daha da azaltabilir.

TPC, TPH'ye benzer performans özelliklerine sahiptir, ancak bu işlem birkaç tablo içerdiğinden tüm türlerin varlıkları seçilirken biraz daha yavaştır. Ancak, TPC tek yaprak türünde varlıkları sorgularken gerçekten çok başarılı olur. Sorgu yalnızca tek bir tablo kullanır ve filtreleme gerektirmez.

Somut bir örnek için, 7 tür hiyerarşisi ile basit bir model ayarlayan bu karşılaştırmaya bakın; her tür için 5000 satır (toplam 35000 satır) dağıtılır ve karşılaştırma yalnızca veritabanındaki tüm satırları yükler:

Yöntem Ortalama Hata Stdsapma 0. Nesil 1. Nesil Tahsis edilen
TPH 149,0 ms 3,38 ms 9,80 ms 4000.0000 1000.0000 40 MB
TPT 312,9 ms 6,17 ms 10,81 ms 9000.0000 3000.0000 75 MB
TPC 158,2 ms 3,24 ms 8,88 ms 5000.0000 2000.0000 46 MB

Görüldüğü gibi, TPH ve TPC bu senaryo için TPT'den çok daha verimlidir. Gerçek sonuçların her zaman yürütülen belirli sorguya ve hiyerarşideki tablo sayısına bağlı olduğunu, dolayısıyla diğer sorguların farklı bir performans boşluğu gösterebileceğini unutmayın; Bu karşılaştırma kodunu diğer sorguları test etmek için şablon olarak kullanmanız tavsiye edilir.