Verimli Sorgulama

Verimli bir şekilde sorgulama, dizinler, ilgili varlık yükleme stratejileri ve diğerleri gibi geniş kapsamlı konuları kapsayan geniş bir konudur. Bu bölümde, sorgularınızı daha hızlı hale getirmek için bazı yaygın temalar ve kullanıcıların genellikle karşılaştığı tuzaklar ayrıntılı olarak açıklanmıştır.

Dizinleri düzgün kullanma

Sorgunun hızlı çalıştırılıp çalıştırılmayacağına karar veren temel faktör, uygun olduğunda dizinleri düzgün kullanıp kullanmayacağıdır: veritabanları genellikle büyük miktarda veriyi tutmak için kullanılır ve tabloların tamamında geçiş yapan sorgular genellikle ciddi performans sorunlarının kaynaklarıdır. Dizin oluşturma sorunlarını saptamak kolay değildir, çünkü belirli bir sorguda dizin kullanılıp kullanılmayacağı hemen belli olmaz. Örnek:

// Matches on start, so uses an index (on SQL Server)
var posts1 = context.Posts.Where(p => p.Title.StartsWith("A")).ToList();
// Matches on end, so does not use the index
var posts2 = context.Posts.Where(p => p.Title.EndsWith("A")).ToList();

Dizin oluşturma sorunlarını tespit etmenin iyi bir yolu, önce yavaş bir sorguyu saptamak ve ardından veritabanınızın sık kullanılan aracı aracılığıyla sorgu planını incelemektir; Bunun nasıl yapacağı hakkında daha fazla bilgi için performans tanılama sayfasına bakın. Sorgu planı, sorgunun tablonun tamamında geçiş yapıp yapmadığını veya dizin kullanıp kullanmadığını görüntüler.

Genel bir kural olarak, dizinleri kullanmak veya bunlarla ilgili performans sorunlarını tanılamak için özel bir EF bilgisi yoktur; dizinler ile ilgili genel veritabanı bilgileri, EF kullanmayan uygulamalarla olduğu kadar EF uygulamalarıyla da ilgilidir. Dizinleri kullanırken göz önünde bulundurulması gereken bazı genel yönergeler aşağıda listelenmektedir:

  • Dizinler sorguları hızlandırırken, güncel tutulması gerektiğinden güncelleştirmeleri de yavaşlatır. Gerekli olmayan dizinleri tanımlamaktan kaçının ve dizini satırların bir alt kümesiyle sınırlandırmak için dizin filtrelerini kullanmayı göz önünde bulundurarak bu ek yükü azaltın.
  • Bileşik dizinler, birden çok sütuna göre filtreleyen sorguları hızlandırabilir, ancak sıralamaya bağlı olarak dizinin tüm sütunlarında filtrelemeyen sorguları da hızlandırabilir. Örneğin, A ve B sütunlarında bir dizin, A ve B'ye göre filtrelemeyi hızlandıran sorguların yanı sıra yalnızca A'ya göre filtre uygulanan sorguları hızlandırır, ancak yalnızca B üzerinden filtrelemeyi hızlandırmaz.
  • Bir sorgu bir sütun üzerinde bir ifadeye göre filtrelerse (örneğin price / 2), basit bir dizin kullanılamaz. Ancak, ifadeniz için depolanan kalıcı bir sütun tanımlayabilir ve bunun üzerinde bir dizin oluşturabilirsiniz. Bazı veritabanları, herhangi bir ifadeye göre sorguları filtrelemeyi hızlandırmak için doğrudan kullanılabilen ifade dizinlerini de destekler.
  • Farklı veritabanları dizinlerin çeşitli şekillerde yapılandırılmasına izin verir ve çoğu durumda EF Core sağlayıcıları bunları Fluent API aracılığıyla kullanıma sunar. Örneğin, SQL Server sağlayıcısı bir dizinin kümelenmiş olup olmadığını yapılandırmanıza veya doldurma faktörünü ayarlamanıza olanak tanır. Daha fazla bilgi için sağlayıcınıza başvurun.

Yalnızca ihtiyacınız olan özellikleri projele

EF Core, varlık örneklerini sorgulamayı ve ardından bu örnekleri kodda kullanmayı çok kolaylaştırır. Ancak varlık örneklerini sorgulamak, veritabanınızdan gerektiğinden daha fazla veriyi sık sık geri çekebilir. Aşağıdakileri göz önünde bulundurun:

foreach (var blog in context.Blogs)
{
    Console.WriteLine("Blog: " + blog.Url);
}

Bu kod yalnızca her Blog'un Url özelliğine ihtiyaç duyar, ancak Blog varlığının tamamı getirilir ve gereksiz sütunlar veritabanından aktarılır:

SELECT [b].[BlogId], [b].[CreationDate], [b].[Name], [b].[Rating], [b].[Url]
FROM [Blogs] AS [b]

Bu, EF'ye hangi sütunları yansıtacaklarını bildirmek için kullanılarak Select iyileştirilebilir:

foreach (var blogName in context.Blogs.Select(b => b.Url))
{
    Console.WriteLine("Blog: " + blogName);
}

Sonuçta elde edilen SQL yalnızca gerekli sütunları geri çeker:

SELECT [b].[Url]
FROM [Blogs] AS [b]

Birden fazla sütun yansıtmanız gerekiyorsa, istediğiniz özellikleri içeren bir C# anonim türüne yansıtın.

Bu tekniğin salt okunur sorgular için çok yararlı olduğunu, ancak EF'nin değişiklik izlemesinin yalnızca varlık örnekleriyle çalıştığından, getirilen blogları güncelleştirmeniz gerektiğinde işlerin daha karmaşık hale geldiğini unutmayın. Değiştirilmiş bir Blog örneği ekleyerek ve EF'e hangi özelliklerin değiştiğini belirterek varlıkların tamamını yüklemeden güncelleştirmeler gerçekleştirmek mümkündür, ancak bu, buna değmeyecek daha gelişmiş bir tekniktir.

Sonuç kümesi boyutunu sınırlama

Varsayılan olarak, sorgu filtreleri ile eşleşen tüm satırları döndürür:

var blogsAll = context.Posts
    .Where(p => p.Title.StartsWith("A"))
    .ToList();

Döndürülen satır sayısı veritabanınızdaki gerçek verilere bağlı olduğundan, veritabanından ne kadar veri yüklendiğini, sonuçlar tarafından ne kadar bellek alınacağını ve bu sonuçlar işlenirken ne kadar ek yük oluşturulacağını (örneğin, ağ üzerinden bir kullanıcı tarayıcısına göndererek) bilmek mümkün değildir. Test veritabanlarında genellikle çok az veri bulunduğundan test sırasında her şey düzgün çalışır ancak sorgu gerçek dünya verilerinde çalışmaya başladığında ve birçok satır döndürülürken performans sorunları aniden ortaya çıkar.

Sonuç olarak, genellikle sonuç sayısını sınırlamayı düşünmek faydalı olur:

var blogs25 = context.Posts
    .Where(p => p.Title.StartsWith("A"))
    .Take(25)
    .ToList();

Kullanıcı arabiriminiz en azından veritabanında daha fazla satır olabileceğini belirten bir ileti gösterebilir (ve bunların başka bir şekilde alınmasına izin verebilir). Tam kapsamlı bir çözüm, kullanıcı arabiriminizin aynı anda yalnızca belirli sayıda satırı gösterdiği ve kullanıcıların gerektiğinde bir sonraki sayfaya ilerlemesine olanak sağlayan sayfalandırma uygular; bunun verimli bir şekilde nasıl uygulanacağı hakkında daha fazla bilgi için sonraki bölüme bakın.

Verimli sayfalandırma

Sayfalandırma, sonuçların bir kerede değil, sayfalarda alınmasını ifade eder; bu genellikle, kullanıcının sonuçların sonraki veya önceki sayfasına gitmesine izin veren bir kullanıcı arabiriminin gösterildiği büyük sonuç kümeleri için yapılır. Veritabanlarıyla sayfalandırma uygulamanın yaygın yollarından biri ve Take işleçlerini (OFFSETve LIMIT SQL'de) kullanmaktırSkip; bu sezgisel bir uygulama olsa da, oldukça verimsizdir. Tek seferde bir sayfa taşımaya izin veren sayfalandırma için (rastgele sayfalara atlamak yerine), bunun yerine anahtar kümesi sayfalandırmayı kullanmayı göz önünde bulundurun.

Daha fazla bilgi için sayfalandırma ile ilgili belgeler sayfasına bakın.

İlişkisel veritabanlarında, tek sorguda JOIN'ler tanıtılarak tüm ilgili varlıklar yüklenir.

SELECT [b].[BlogId], [b].[OwnerId], [b].[Rating], [b].[Url], [p].[PostId], [p].[AuthorId], [p].[BlogId], [p].[Content], [p].[Rating], [p].[Title]
FROM [Blogs] AS [b]
LEFT JOIN [Post] AS [p] ON [b].[BlogId] = [p].[BlogId]
ORDER BY [b].[BlogId], [p].[PostId]

Tipik bir blogda birden çok ilgili gönderi varsa, bu gönderilerin satırları blog bilgilerini yineler. Bu yineleme"kartezyen patlama" sorununa yol açar. Bire çok ilişkiler yüklendikçe yinelenen veri miktarı artabilir ve uygulamanızın performansını olumsuz etkileyebilir.

EF, ilgili varlıkları ayrı sorgular aracılığıyla yükleyen "bölünmüş sorgular" kullanarak bu etkiyi önlemeye olanak tanır. Daha fazla bilgi için bölünmüş ve tek sorgular hakkındaki belgeleri okuyun.

Dekont

Bölünmüş sorguların geçerli uygulaması her sorgu için bir gidiş dönüş yürütür. Gelecekte bunu iyileştirmeyi ve tüm sorguları tek bir gidiş dönüşte yürütmeyi planlıyoruz.

Bu bölüme devam etmeden önce ilgili varlıklardaki ayrılmış sayfayı okuması önerilir.

İlgili varlıklarla ilgilenirken genellikle neleri yüklememiz gerektiğini önceden biliyoruz: Tipik bir örnek, tüm Gönderileriyle birlikte belirli bir Blog kümesi yüklemek olabilir. Bu senaryolarda, EF'in tüm gerekli verileri tek bir gidiş dönüşte getirebilmesi için istekli yüklemeyi kullanmak her zaman daha iyidir. Filtrelenen ekleme özelliği ayrıca hangi ilgili varlıkları yüklemek istediğinizi sınırlamanıza olanak tanırken yükleme işleminin istekli olmasını sağlar ve bu nedenle tek bir gidiş dönüşte yapılabilir:

using (var context = new BloggingContext())
{
    var filteredBlogs = context.Blogs
        .Include(
            blog => blog.Posts
                .Where(post => post.BlogId == 1)
                .OrderByDescending(post => post.Title)
                .Take(5))
        .ToList();
}

Diğer senaryolarda, asıl varlığını almadan önce hangi ilgili varlığa ihtiyacımız olacağını bilemeyebiliriz. Örneğin, bazı Blogları yüklerken, blog gönderileriyle ilgilenip ilgilenmediğimiz konusunda bilgi edinmek için başka bir veri kaynağına (muhtemelen bir web hizmeti) başvurmamız gerekebilir. Böyle durumlarda, ilgili varlıkları ayrı ayrı getirmek ve Blog'un Gönderiler gezintisini doldurmak için açık veya gecikmeli yükleme kullanılabilir. Bu yöntemlerin istekli olmadığından, yavaşlama kaynağı olan veritabanına ek gidiş dönüşler gerektirdiğini unutmayın; belirli senaryonuza bağlı olarak, ek gidiş dönüşleri yürütmek ve yalnızca ihtiyacınız olan Gönderileri seçmeli olarak almak yerine her zaman tüm Gönderileri yüklemek daha verimli olabilir.

Gecikmeli yüklemeye dikkat edin

EF Core, kodunuz tarafından erişildikçe veritabanındaki ilgili varlıkları otomatik olarak yüklediğinden, yavaş yükleme genellikle veritabanı mantığı yazmanın çok yararlı bir yolu gibi görünür. Bu, gerekli olmayan ilgili varlıkların yüklenmesini önler (açıkça yükleme gibi) ve programcıyı ilgili varlıklarla tamamen ilgilenmek zorunda bırakmaz. Ancak, yavaş yükleme özellikle uygulamayı yavaşlatabilecek gereksiz ek gidiş dönüşler üretmeye eğilimli.

Aşağıdakileri göz önünde bulundurun:

foreach (var blog in context.Blogs.ToList())
{
    foreach (var post in blog.Posts)
    {
        Console.WriteLine($"Blog {blog.Url}, Post: {post.Title}");
    }
}

Bu görünüşte masum görünen kod parçası, tüm bloglarda ve gönderilerinde yineleme yaparak bunları yazdırıyor. EF Core'un deyim günlüğünü açtığınızda aşağıdakiler ortaya çıkar:

info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [b].[BlogId], [b].[Rating], [b].[Url]
      FROM [Blogs] AS [b]
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (5ms) [Parameters=[@__p_0='1'], CommandType='Text', CommandTimeout='30']
      SELECT [p].[PostId], [p].[BlogId], [p].[Content], [p].[Title]
      FROM [Post] AS [p]
      WHERE [p].[BlogId] = @__p_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[@__p_0='2'], CommandType='Text', CommandTimeout='30']
      SELECT [p].[PostId], [p].[BlogId], [p].[Content], [p].[Title]
      FROM [Post] AS [p]
      WHERE [p].[BlogId] = @__p_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[@__p_0='3'], CommandType='Text', CommandTimeout='30']
      SELECT [p].[PostId], [p].[BlogId], [p].[Content], [p].[Title]
      FROM [Post] AS [p]
      WHERE [p].[BlogId] = @__p_0

... and so on

Neler oluyor burada? Yukarıdaki basit döngüler için neden tüm bu sorgular gönderiliyor? Yavaş yüklemeyle, blog gönderileri yalnızca Gönderiler özelliğine erişildiğinde yüklenir; Sonuç olarak, iç foreach içindeki her yineleme kendi gidiş dönüşlerinde ek bir veritabanı sorgusu tetikler. Sonuç olarak, ilk sorgu tüm blogları yükledikten sonra blog başına başka bir sorgumuz olur ve tüm gönderilerini yükleriz; bu bazen N+1 sorunu olarak adlandırılır ve çok önemli performans sorunlarına neden olabilir.

Blogların tüm gönderilerine ihtiyacımız olacağını varsayarsak, bunun yerine burada hevesle yüklemeyi kullanmak mantıklıdır. Yüklemeyi gerçekleştirmek için Include işlecini kullanabiliriz, ancak yalnızca Blogların URL'lerine ihtiyacımız olduğundan (ve yalnızca gerekenleri yüklemeliyiz). Bunun yerine bir projeksiyon kullanacağız:

foreach (var blog in context.Blogs.Select(b => new { b.Url, b.Posts }).ToList())
{
    foreach (var post in blog.Posts)
    {
        Console.WriteLine($"Blog {blog.Url}, Post: {post.Title}");
    }
}

Bu, EF Core'un tüm Blogları ve Gönderilerini tek bir sorguda getirmesini sağlar. Bazı durumlarda bölünmüş sorgular kullanarak kartezyen patlama etkilerini önlemek de yararlı olabilir.

Uyarı

Yavaş yükleme, N+1 sorununu yanlışlıkla tetiklemesini son derece kolaylaştırdığından, bu sorundan kaçınması önerilir. İstekli veya açık yükleme, bir veritabanı gidiş dönüş gerçekleştiğinde kaynak kodda bunu çok net hale getirir.

Arabelleğe alma ve akış

Arabelleğe alma, tüm sorgu sonuçlarınızın belleğe yüklenmesini ifade ederken akış, EF'nin uygulamayı her seferinde tek bir sonuçla tutması ve hiçbir zaman tüm sonuç kümesini bellekte içermemesi anlamına gelir. İlke olarak, akış sorgusunun bellek gereksinimleri sabittir; sorgu 1 satır veya 1000 döndürse de aynıdır; bir arabelleğe alma sorgusu ise daha fazla satır döndürülürken daha fazla bellek gerektirir. Büyük sonuç kümeleri elde eden sorgular için bu önemli bir performans faktörü olabilir.

Sorgu arabelleğinin mi yoksa akışların mı değerlendirildiğine bağlıdır:

// ToList and ToArray cause the entire resultset to be buffered:
var blogsList = context.Posts.Where(p => p.Title.StartsWith("A")).ToList();
var blogsArray = context.Posts.Where(p => p.Title.StartsWith("A")).ToArray();

// Foreach streams, processing one row at a time:
foreach (var blog in context.Posts.Where(p => p.Title.StartsWith("A")))
{
    // ...
}

// AsEnumerable also streams, allowing you to execute LINQ operators on the client-side:
var doubleFilteredBlogs = context.Posts
    .Where(p => p.Title.StartsWith("A")) // Translated to SQL and executed in the database
    .AsEnumerable()
    .Where(p => SomeDotNetMethod(p)); // Executed at the client on all database results

Sorgularınız yalnızca birkaç sonuç döndürecekse, büyük olasılıkla bu konuda endişelenmeniz gerekmez. Ancak sorgunuz çok sayıda satır döndürebilirse arabelleğe almak yerine akışa almayı düşünmeniz faydalı olabilir.

Dekont

Sonuç üzerinde başka bir LINQ işleci kullanmak istiyorsanız veya ToArray kullanmaktan ToList kaçının; bu işlem gereksiz bir şekilde tüm sonuçları belleğe arabelleğe alır. Bunun yerine AsEnumerable kullanın.

EF tarafından iç arabelleğe alma

Bazı durumlarda, sorgunuzu nasıl değerlendirdiğinize bakılmaksızın EF, sonuç kümesini dahili olarak arabelleğe alır. Bunun gerçekleştiği iki durum şunlardır:

  • Yeniden deneme yürütme stratejisi uygulandığında. Bu, sorgu daha sonra yeniden denenirse aynı sonuçların döndürülmesini sağlamak için yapılır.
  • Bölme sorgusu kullanıldığında, SQL Server'da MARS (Birden Çok Etkin Sonuç Kümesi) etkinleştirilmediği sürece, son sorgu dışındaki tüm sonuç kümeleri arabelleğe alınır. Bunun nedeni, aynı anda birden çok sorgu sonuç kümesi etkinleştirmenin genellikle imkansız olmasıdır.

Bu iç arabelleğe alma işleminin LINQ işleçleri aracılığıyla neden olduğunuz tüm arabelleğe alma işlemlerine ek olarak oluştuğuna dikkat edin. Örneğin, sorguda kullanıyorsanız ToList ve yeniden deneme yürütme stratejisi uygulanıyorsa sonuç kümesi belleğe iki kez yüklenir: EF tarafından dahili olarak bir kez ve tarafından bir kez ToList.

İzleme, izleme ve kimlik çözümleme

Bu bölüme devam etmeden önce izleme ve izleme yapılmama ile ilgili ayrılmış sayfayı okumanızı öneririz.

EF, varlık örneklerini varsayılan olarak izler, böylece bunlardaki değişiklikler çağrıldığında SaveChanges algılanır ve kalıcı hale gelir. Sorguları izlemenin bir diğer etkisi de EF'in verileriniz için bir örneğin önceden yüklenip yüklenmediğini algılaması ve yeni bir örnek döndürmek yerine bu izlenen örneği otomatik olarak döndürmesidir; buna kimlik çözümleme denir. Performans açısından bakıldığında değişiklik izleme şu anlama gelir:

  • EF, izlenen örneklerin sözlüğünü dahili olarak tutar. Yeni veriler yüklendiğinde, EF sözlüğünü denetleerek bir örneğin söz konusu varlığın anahtarı (kimlik çözümlemesi) için zaten izlenip izlenmediğini denetler. Sorgunun sonuçları yüklenirken sözlük bakımı ve aramaları biraz zaman alır.
  • Yüklü bir örneği uygulamaya teslim etmeden önce, EF bu örneği anlık görüntüler ve anlık görüntüyü dahili olarak tutar. Çağrıldığında SaveChanges , kalıcı olacak değişiklikleri bulmak için uygulamanın örneği anlık görüntüyle karşılaştırılır. Anlık görüntü daha fazla bellek alır ve anlık görüntü oluşturma işleminin kendisi zaman alır; bazen değer karşılaştırıcılar aracılığıyla farklı, büyük olasılıkla daha verimli anlık görüntü oluşturma davranışı belirtmek veya anlık görüntü oluşturma işlemini tamamen atlamak için değişiklik izleme proxy'lerini kullanmak mümkündür (ancak bu kendi dezavantajları kümesiyle birlikte gelir).

Değişikliklerin veritabanına geri kaydedilmediği salt okunur senaryolarda, izleme olmayan sorgular kullanılarak yukarıdaki ek yüklerden kaçınılabilir. Ancak, izlemesiz sorgular kimlik çözümlemesi gerçekleştirmediğinden, birden çok başka yüklenen satır tarafından başvurulan bir veritabanı satırı farklı örnekler olarak gerçekleştirilir.

Bunu göstermek için, veritabanından çok sayıda Gönderi ve her Gönderi tarafından başvuruda bulunılan Blog'un yüklendiğini varsayalım. 100 Gönderi aynı Blog'a başvuruda bulunursa, bir izleme sorgusu bunu kimlik çözümlemesi aracılığıyla algılar ve tüm Post örnekleri aynı yinelenenleri kaldırılmış Blog örneğine başvurur. Buna karşılık, izleme olmayan bir sorgu aynı Blogu 100 kez yineler ve uygulama kodu buna göre yazılmalıdır.

Aşağıda, her birinde 20 Gönderi bulunan 10 Blog yükleyerek bir sorgu için izleme karşılaştırması ve izlememe davranışı karşılaştırmasının sonuçları yer alır. Kaynak kodu burada bulabilirsiniz, kendi ölçümleriniz için temel olarak kullanmaktan çekinmeyin.

Metot NumBlogs NumPostsPerBlog Ortalama Hata Stdsapma Ortanca Oran RatioSD 0. Nesil 1. Nesil 2. Nesil Tahsis edilen
AsTracking 10 20 1,414,7 bize 27.20 bize 45.44 bize 1,405,5 biz 1,00 Kategori 0.00 60.5469 13.6719 - 380,11 KB
AsNoTracking 10 20 993.3 bize 24.04 bize 65.40 bize 966.2 biz 0.71 0.05 37.1094 6.8359 - 232,89 KB

Son olarak, izleme yok sorgusu kullanarak ve sonra döndürülen örneği bağlama ekleyerek, hangi değişikliklerin yapılması gerektiğini belirterek değişiklik izleme yükü olmadan güncelleştirmeleri gerçekleştirmek mümkündür. Bu, değişiklik izleme yükünü EF'ten kullanıcıya aktarır ve yalnızca değişiklik izleme ek yükünün profil oluşturma veya karşılaştırma yoluyla kabul edilemez olduğu gösterilmişse denenmelidir.

SQL sorgularını kullanma

Bazı durumlarda, sorgunuz için EF'in oluşturmadığı daha iyileştirilmiş SQL vardır. SQL yapısı veritabanınıza özgü desteklenmeyen bir uzantı olduğunda veya EF henüz buna çevrilmediğinde bu durum oluşabilir. Bu gibi durumlarda SQL'i el ile yazmak önemli bir performans artışı sağlayabilir ve EF bunu yapmanın çeşitli yollarını destekler.

  • SQL sorgularını doğrudan sorgunuzda kullanın; örneğin aracılığıyla FromSqlRaw. EF, normal LINQ sorguları ile SQL üzerinden oluşturmanızı sağlar ve SQL'de sorgunun yalnızca bir bölümünü ifade etmenizi sağlar. SQL'in kod tabanınızdaki tek bir sorguda kullanılması gerektiğinde bu iyi bir tekniktir.
  • Kullanıcı tanımlı bir işlev (UDF) tanımlayın ve sorgularınızdan bunu çağırarak. EF'nin UDF'lerin tablo değerli işlevler (TVF' ler) olarak bilinen tam sonuç kümeleri döndürmesine izin verdiğine ve bir işlevin eşlenip DbSet aynı başka bir tablo gibi görünmesine izin verdiğine dikkat edin.
  • Sorgularınızda bir veritabanı görünümü ve sorgu tanımlayın. İşlevlerden farklı olarak görünümlerin parametreleri kabul edemeyeceğini unutmayın.

Dekont

Ham SQL genellikle EF'in istediğiniz SQL'i oluşturamamasını sağladıktan sonra ve belirli bir sorgunun bunu haklı çıkarabilmesi için performans yeterince önemli olduğunda son çare olarak kullanılmalıdır. Ham SQL kullanmak önemli bakım dezavantajları getirir.

Zaman uyumsuz programlama

Genel bir kural olarak, uygulamanızın ölçeklenebilir olması için zaman uyumlu api yerine her zaman zaman uyumsuz API'ler kullanmak önemlidir (örneğin SaveChangesAsyncSaveChangesyerine). Zaman uyumlu API'ler, veritabanı G/Ç süresi boyunca iş parçacığını engelleyip iş parçacıklarına olan ihtiyacı ve gerçekleşmesi gereken iş parçacığı bağlam anahtarlarının sayısını artırır.

Daha fazla bilgi için zaman uyumsuz programlama sayfasına bakın.

Uyarı

Aynı uygulamada zaman uyumlu ve zaman uyumsuz kodu karıştırmaktan kaçının; istemeden hafif iş parçacığı havuzu yetersizliği sorunlarını tetikleme çok kolaydır.

Uyarı

Microsoft.Data.SqlClient'ın zaman uyumsuz uygulamasında ne yazık ki bazı bilinen sorunlar vardır (örneğin, #593, #601 ve diğerleri). Beklenmeyen performans sorunlarıyla karşı karşıyaysanız, özellikle büyük metin veya ikili değerlerle ilgilenirken bunun yerine eşitleme komutu yürütmeyi kullanmayı deneyin.

Ek kaynaklar