Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
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. Örneğin:
// Matches on start, so uses an index (on SQL Server)
var posts1 = await context.Posts.Where(p => p.Title.StartsWith("A")).ToListAsync();
// Matches on end, so does not use the index
var posts2 = await context.Posts.Where(p => p.Title.EndsWith("A")).ToListAsync();
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, up-togü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:
await foreach (var blog in context.Blogs.AsAsyncEnumerable())
{
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 durum, EF'ye hangi sütunların yansıtılacağını belirtmek için Select
kullanılarak optimize edilebilir.
await foreach (var blogName in context.Blogs.Select(b => b.Url).AsAsyncEnumerable())
{
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 = await context.Posts
.Where(p => p.Title.StartsWith("A"))
.ToListAsync();
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 = await context.Posts
.Where(p => p.Title.StartsWith("A"))
.Take(25)
.ToListAsync();
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 izin veren sayfalandırma uygular; Bunu verimli bir şekilde uygulama 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 Skip
ve Take
işleçlerini kullanmaktır (OFFSET
ve LIMIT
SQL'de); 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.
İlgili varlıkları yüklerken kartezyen patlamasından kaçını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.
Uyarı
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.
Mümkün olduğunda ilgili varlıkları hevesle yükleme
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 = await context.Blogs
.Include(
blog => blog.Posts
.Where(post => post.BlogId == 1)
.OrderByDescending(post => post.Title)
.Take(5))
.ToListAsync();
}
Diğer senaryolarda, asıl varlığı edinmeden ö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, ilişkili varlıkları ayrı ayrı almak ve Blog'un Gönderi 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 await context.Blogs.ToListAsync())
{
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? Lazy loading ile, bir blogun gönderileri yalnızca Gönderiler özelliğine erişildiğinde (tembelce) yüklenir. Sonuç olarak, iç foreach döngüsündeki her yineleme, kendi başına ek bir gidiş-dönüş veritabanı sorgusu tetikler. Sonuç olarak, ilk sorgu tüm blogları yükledikten sonra blog başına tüm gönderilerini yüken başka bir sorgumuz olur; Bu bazen N+1 sorunu olarak adlandırılır ve çok önemli performans sorunlarına neden olabilir.
Eğer blogların tüm gönderilerine ihtiyacımız olacağını varsayıyorsak, bunun yerine burada hemen yükleme 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:
await foreach (var blog in context.Blogs.Select(b => new { b.Url, b.Posts }).AsAsyncEnumerable())
{
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 video akışı
Arabelleğe alma, sorgu sonuçlarınızın tümünü belleğe yüklemek anlamına gelirken, akış modu, EF'nin her seferinde uygulamaya tek bir sonuç sağlaması ve sonuç kümesinin hiçbir zaman tamamını bellekte bulundurmaması 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 = await context.Posts.Where(p => p.Title.StartsWith("A")).ToListAsync();
var blogsArray = await context.Posts.Where(p => p.Title.StartsWith("A")).ToArrayAsync();
// Foreach streams, processing one row at a time:
await foreach (var blog in context.Posts.Where(p => p.Title.StartsWith("A")).AsAsyncEnumerable())
{
// ...
}
// AsAsyncEnumerable 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
.AsAsyncEnumerable()
.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ürebilecekse, arabelleğe almak yerine akışı tercih etmek faydalı olabilir.
Uyarı
ToList veya ToArray kullanmaktan kaçının; çünkü bu, sonuçlar üzerinde başka bir LINQ işleci kullanmayı planladığınızda tüm sonuçları gereksiz yere 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 devrede olduğunda. 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 ToList kullanıyorsanız ve bir yeniden deneme yürütme stratejisi uygulanıyorsa, sonuç kümesi belleğe iki kez yüklenir: bir kez EF tarafından dahili olarak ve bir kez de ToList tarafından.
İzleme, izlenmeme 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üğü denetleyerek bir örneğin söz konusu varlığın anahtarına (kimlik çözümlemesi) göre zaten izlenip izlenmediğini kontrol eder. Sorgunun sonuçları yüklenirken sözlük bakımı ve aramaları biraz zaman alır.
- Uygulamaya yüklü bir durumu teslim etmeden önce, EF bu durumu anlık görüntüler ve bu 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, takipsiz sorgular kimlik çözümlemesi gerçekleştirmediğinden, birden çok başka yüklenen satır tarafından başvuruda bulunulan bir veritabanı satırı farklı örnekler olarak kullanılır.
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şvurduğunda, bir izleme sorgusu kimlik çözümlemesi aracılığıyla bunu algılar ve tüm Gönderi örnekleri aynı benzersiz hale getirilmiş Blog örneğine referans verir. Buna karşılık, izleme olmayan bir sorgu aynı Blogu 100 kez yineler ve uygulama kodu buna göre yazılmalıdır.
Burada, her birinde 20 Gönderi bulunan 10 Blog yüklemesi yapan bir sorgu için izlenirlik ve izlenmezliğin karşılaştırılması sonuçları yer almaktadır. Kaynak kodu burada bulabilirsiniz, kendi ölçümleriniz için temel olarak kullanmaktan çekinmeyin.
Yöntem | NumBlogs | NumPostsPerBlog | Ortalama | Hata | StdDev | Medyan | 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 | 0,00 | 60,5469 | 13.6719 | - | 380,11 KB |
AsNoTracking (İzleme olmadan) | 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, izlenmeyen bir sorgu kullanarak ve ardından 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üncellemeleri 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ızda bu işlevi çağırın. 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.
Uyarı
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, zamansal uyumlu API yerine her zaman zamansal uyumsuz API'ler kullanmak önemlidir (örneğin SaveChangesAsyncSaveChanges yerine). Senkron API'ler, veritabanı G/Ç süresi boyunca iş parçacığını engelleyerek iş parçacıklarına olan ihtiyacı ve gerçekleşmesi gereken iş parçacığı bağlam geçişlerinin sayısını artırır.
Daha fazla bilgi için zaman uyumsuz programlama sayfasına bakın.
Uyarı
Aynı uygulamada eşzamanlı ve eşzamansız kodu karıştırmaktan kaçının; fark edilmesi zor iş parçacığı havuzu yetersizliği sorunlarını istemeden tetiklemek çok kolaydır.
Uyarı
Microsoft.Data.SqlClient asenkron uygulamasında ne yazık ki bazı bilinen sorunlar vardır (örneğin #593, #601ve 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
- Verimli sorgulamayla ilgili ek konular için gelişmiş performans konuları sayfasına bakın.
- Nullable değerleri karşılaştırırken en iyi yöntemler için null karşılaştırma belge sayfasının performans bölümüne bakın.