Aracılığıyla paylaş


Gelişmiş Performans Konuları

DbContext havuzu oluşturma

A DbContext genellikle basit bir nesnedir: bir veritabanı işlemi oluşturma ve yok etme işlemi içermez ve çoğu uygulama bunu performans üzerinde belirgin bir etki olmadan yapabilir. Ancak, her bağlam örneği görevlerini gerçekleştirmek için gerekli çeşitli iç hizmetleri ve nesneleri ayarlar ve bunu sürekli yapma yükü yüksek performanslı senaryolarda önemli olabilir. Bu durumlarda, EF Core bağlam örneklerinizi havuza alabilir: Bağlamınızı attığınızda EF Core durumunu sıfırlar ve bir iç havuzda depolar; yeni bir örnek istendiğinde, yeni bir örnek ayarlamak yerine havuza alınan örnek döndürülür. Bağlam havuzu, bağlam kurulum maliyetlerini sürekli olarak değil, program başlangıcında yalnızca bir kez ödemenize olanak tanır.

Bağlam havuzunun, veritabanı sürücüsünde daha düşük bir düzeyde yönetilen veritabanı bağlantı havuzuna ortogonal olduğunu unutmayın.

EF Core kullanan bir ASP.NET Core uygulamasındaki tipik desen, aracılığıyla AddDbContextbağımlılık ekleme kapsayıcısına özel DbContext bir tür kaydetmeyi içerir. Ardından, bu türdeki örnekler denetleyicilerdeki veya Razor Sayfalarındaki oluşturucu parametreleri aracılığıyla elde edilir.

Bağlam havuzunu etkinleştirmek için değerini ile AddDbContextPooldeğiştirmeniz AddDbContext yeterlidir:

builder.Services.AddDbContextPool<WeatherForecastContext>(
    o => o.UseSqlServer(builder.Configuration.GetConnectionString("WeatherForecastContext")));

poolSize parametresiAddDbContextPool, havuz tarafından tutulan en fazla örnek sayısını ayarlar (varsayılan olarak 1024'tür). Bir kez poolSize aşıldığında, yeni bağlam örnekleri önbelleğe alınmaz ve EF isteğe bağlı örnek oluşturmanın havuz dışı davranışına geri döner.

Karşılaştırmalar

Aşağıda, bağlam havuzuyla ve bağlam havuzu olmadan aynı makinede yerel olarak çalışan bir SQL Server veritabanından tek bir satır getirmeye yönelik karşılaştırma sonuçları yer almaktadır. Her zaman olduğu gibi sonuçlar satır sayısı, veritabanı sunucunuzdaki gecikme süresi ve diğer faktörlerle değişir. Daha da önemlisi, bu tek iş parçacıklı havuz performansını kıyaslarken, gerçek dünyada iddialı bir senaryo farklı sonuçlara sahip olabilir; herhangi bir karar vermeden önce platformunuzda karşılaştırma yapın. Kaynak kodu burada bulabilirsiniz, kendi ölçümleriniz için temel olarak kullanmaktan çekinmeyin.

Metot NumBlogs Ortalama Hata StdDev 0. Nesil 1. Nesil 2. Nesil Tahsis edilen
WithoutContextPooling 1 701.6 bize 26.62 bize 78.48 bize 11.7188 - - 50,38 KB
WithContextPooling 1 350.1 biz 6.80 bize 14.64 bize 0.9766 - - 4,63 KB

Havuza alınan bağlamlarda durumu yönetme

Bağlam havuzu, istekler arasında aynı bağlam örneğini yeniden kullanarak çalışır; bu, tekil olarak etkili bir şekilde kaydedildiği ve aynı örneğin birden çok istekte (veya DI kapsamlarında) yeniden kullanıldığı anlamına gelir. Bu, bağlam istekler arasında değişebilecek herhangi bir durumu içerdiğinde özel özen gösterilmesi gerektiği anlamına gelir. Kritik öneme sahip olan bağlam OnConfiguring yalnızca bir kez çağrılır ( örnek bağlamı ilk oluşturulduğunda) ve bu nedenle değişiklik göstermesi gereken durumu ayarlamak için kullanılamaz (örneğin, kiracı kimliği).

Bağlam durumunu içeren tipik bir senaryo, bağlam örneğinin sorgular tarafından hesaba katılmış bir kiracı kimliğine sahip olduğu çok kiracılı bir ASP.NET Core uygulaması olacaktır (daha fazla ayrıntı için bkz. Genel Sorgu Filtreleri). Kiracı kimliğinin her web isteğiyle değişmesi gerektiğinden, bağlam havuzuyla çalışmasını sağlamak için bazı ek adımları izlememiz gerekir.

Uygulamanızın, kiracı kimliğini ve kiracıyla ilgili diğer bilgileri sarmalayan kapsamlı ITenant bir hizmet kaydettiğinizi varsayalım:

// Below is a minimal tenant resolution strategy, which registers a scoped ITenant service in DI.
// In this sample, we simply accept the tenant ID as a request query, which means that a client can impersonate any
// tenant. In a real application, the tenant ID would be set based on secure authentication data.
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<ITenant>(sp =>
{
    var tenantIdString = sp.GetRequiredService<IHttpContextAccessor>().HttpContext.Request.Query["TenantId"];

    return tenantIdString != StringValues.Empty && int.TryParse(tenantIdString, out var tenantId)
        ? new Tenant(tenantId)
        : null;
});

Yukarıda belirtildiği gibi, kiracı kimliğini nereden edindiğinize özellikle dikkat edin. Bu, uygulamanızın güvenliğinin önemli bir yönüdür.

Kapsamlı ITenant hizmetimizi aldıktan sonra, her zamanki gibi bir havuz bağlamı fabrikasını Tekil hizmet olarak kaydedin:

builder.Services.AddPooledDbContextFactory<WeatherForecastContext>(
    o => o.UseSqlServer(builder.Configuration.GetConnectionString("WeatherForecastContext")));

Ardından, kaydettiğimiz Singleton fabrikasından havuza alınan bağlamı alan ve kiracı kimliğini kullanıma aldığı bağlam örneklerine ekleyen özel bir bağlam fabrikası yazın:

public class WeatherForecastScopedFactory : IDbContextFactory<WeatherForecastContext>
{
    private const int DefaultTenantId = -1;

    private readonly IDbContextFactory<WeatherForecastContext> _pooledFactory;
    private readonly int _tenantId;

    public WeatherForecastScopedFactory(
        IDbContextFactory<WeatherForecastContext> pooledFactory,
        ITenant tenant)
    {
        _pooledFactory = pooledFactory;
        _tenantId = tenant?.TenantId ?? DefaultTenantId;
    }

    public WeatherForecastContext CreateDbContext()
    {
        var context = _pooledFactory.CreateDbContext();
        context.TenantId = _tenantId;
        return context;
    }
}

Özel bağlam fabrikamızı aldıktan sonra bunu Kapsamlı hizmet olarak kaydedin:

builder.Services.AddScoped<WeatherForecastScopedFactory>();

Son olarak, Scoped fabrikamızdan eklenmek üzere bir bağlam ayarlayın:

builder.Services.AddScoped(
    sp => sp.GetRequiredService<WeatherForecastScopedFactory>().CreateDbContext());

Bu noktada, denetleyicileriniz hakkında hiçbir şey bilmek zorunda kalmadan doğru kiracı kimliğine sahip bir bağlam örneğine otomatik olarak eklenir.

Bu örneğin tam kaynak koduna buradan ulaşabilirsiniz.

Not

EF Core ve ilgili hizmetleri için DbContext iç durumu sıfırlamayı üstlenir ancak genellikle EF'nin dışındaki temel veritabanı sürücüsündeki durumu sıfırlamaz. Örneğin, el ile açar ve ADO.NET durumunu başka bir DbConnection şekilde işlerseniz, bağlam örneğini havuza döndürmeden önce (örneğin bağlantıyı kapatarak) bu durumu geri yüklemek size bağlıdır. Bunun yapılmaması, durumun ilgisiz istekler arasında sızdırılmasına neden olabilir.

Derlenmiş sorgular

EF yürütme için bir LINQ sorgu ağacı aldığında, önce bu ağacı "derlemeli", örneğin ondan SQL üretmelidir. Bu görev ağır bir işlem olduğundan, EF sorguları sorgu ağacı şekline göre önbelleğe alır, böylece aynı yapıya sahip sorgular dahili olarak önbelleğe alınmış derleme çıkışlarını yeniden kullanır. Bu önbelleğe alma, parametre değerleri farklı olsa bile aynı LINQ sorgusunu birden çok kez yürütmenin çok hızlı olmasını sağlar.

Ancak, EF'nin iç sorgu önbelleğini kullanabilmesi için bazı görevleri gerçekleştirmesi gerekir. Örneğin, doğru önbelleğe alınmış sorguyu bulmak için sorgunuzun ifade ağacı önbelleğe alınmış sorguların ifade ağaçlarıyla özyinelemeli olarak karşılaştırılmalıdır. Bu ilk işlemenin yükü, özellikle sorgu yürütmeyle ilişkili diğer maliyetlerle (ağ G/Ç, gerçek sorgu işleme ve veritabanında disk G/Ç...) karşılaştırıldığında EF uygulamalarının çoğunda göz ardı edilebilir. Ancak, bazı yüksek performanslı senaryolarda ortadan kaldırılması istenebilir.

EF, bir LINQ sorgusunun .NET temsilcisine açıkça derlenmesini sağlayan derlenmiş sorguları destekler. Bu temsilci alındıktan sonra, LINQ ifade ağacını sağlamadan sorguyu yürütmek için doğrudan çağrılabilir. Bu teknik, önbellek aramasını atlar ve EF Core'da sorgu yürütmenin en iyi duruma getirilmiş yolunu sağlar. Derlenmiş ve derlenmemiş sorgu performansını karşılaştıran bazı karşılaştırma sonuçları aşağıdadır; herhangi bir karar vermeden önce platformunuzda karşılaştırma yapın. Kaynak kodu burada bulabilirsiniz, kendi ölçümleriniz için temel olarak kullanmaktan çekinmeyin.

Metot NumBlogs Ortalama Hata StdDev 0. Nesil Tahsis edilen
WithCompiledQuery 1 564.2 bize 6.75 bize 5.99 bize 1.9531 9 KB
WithoutCompiledQuery 1 671.6 biz 12.72 biz 16.54 bize 2.9297 13 KB
WithCompiledQuery 10 645.3 bize 10.00 bize 9.35 bize 2.9297 13 KB
WithoutCompiledQuery 10 709.8 biz 25.20 bize 73.10 bize 3.9063 18 KB

Derlenmiş sorguları kullanmak için önce aşağıdakiyle EF.CompileAsyncQuery bir sorgu derleyin (zaman uyumlu sorgular için kullanın EF.CompileQuery ):

private static readonly Func<BloggingContext, int, IAsyncEnumerable<Blog>> _compiledQuery
    = EF.CompileAsyncQuery(
        (BloggingContext context, int length) => context.Blogs.Where(b => b.Url.StartsWith("http://") && b.Url.Length == length));

Bu kod örneğinde EF'e bir örneği kabul eden bir DbContext lambda ve sorguya geçirilecek rastgele bir parametre sunuyoruz. Artık sorguyu yürütmek istediğinizde bu temsilciyi çağırabilirsiniz:

await foreach (var blog in _compiledQuery(context, 8))
{
    // Do something with the results
}

Temsilcinin iş parçacığı açısından güvenli olduğunu ve farklı bağlam örneklerinde eşzamanlı olarak çağrılabileceğini unutmayın.

Sınırlamalar

  • Derlenmiş sorgular yalnızca tek bir EF Core modelde kullanılabilir. Aynı türdeki farklı bağlam örnekleri bazen farklı modeller kullanacak şekilde yapılandırılabilir; bu senaryoda derlenmiş sorguların çalıştırılması desteklenmez.
  • Derlenmiş sorgularda parametreleri kullanırken basit, skaler parametreler kullanın. Örneklerde üye/yöntem erişimi gibi daha karmaşık parametre ifadeleri desteklenmez.

Sorgu önbelleğe alma ve parametreleştirme

EF yürütme için bir LINQ sorgu ağacı aldığında, önce bu ağacı "derlemeli", örneğin ondan SQL üretmelidir. Bu görev ağır bir işlem olduğundan, EF sorguları sorgu ağacı şekline göre önbelleğe alır, böylece aynı yapıya sahip sorgular dahili olarak önbelleğe alınmış derleme çıkışlarını yeniden kullanır. Bu önbelleğe alma, parametre değerleri farklı olsa bile aynı LINQ sorgusunu birden çok kez yürütmenin çok hızlı olmasını sağlar.

Aşağıdaki iki sorguyu göz önünde bulundurun:

var post1 = context.Posts.FirstOrDefault(p => p.Title == "post1");
var post2 = context.Posts.FirstOrDefault(p => p.Title == "post2");

İfade ağaçları farklı sabitler içerdiğinden, ifade ağacı farklılık gösterir ve bu sorguların her biri EF Core tarafından ayrı ayrı derlenir. Buna ek olarak, her sorgu biraz farklı bir SQL komutu üretir:

SELECT TOP(1) [b].[Id], [b].[Name]
FROM [Posts] AS [b]
WHERE [b].[Name] = N'post1'

SELECT TOP(1) [b].[Id], [b].[Name]
FROM [Posts] AS [b]
WHERE [b].[Name] = N'post2'

SQL farklı olduğundan veritabanı sunucunuzun aynı planı yeniden kullanmak yerine her iki sorgu için de bir sorgu planı oluşturması gerekebilir.

Sorgularınızda küçük bir değişiklik yapılması işleri önemli ölçüde değiştirebilir:

var postTitle = "post1";
var post1 = context.Posts.FirstOrDefault(p => p.Title == postTitle);
postTitle = "post2";
var post2 = context.Posts.FirstOrDefault(p => p.Title == postTitle);

Blog adı artık parametreli hale getirildiğinden, her iki sorgu da aynı ağaç şekline sahiptir ve EF'nin yalnızca bir kez derlenmesi gerekir. Üretilen SQL de parametrelendirilerek veritabanının aynı sorgu planını yeniden kullanmasına olanak sağlar:

SELECT TOP(1) [b].[Id], [b].[Name]
FROM [Posts] AS [b]
WHERE [b].[Name] = @__postTitle_0

Her sorguyu parametreleştirmeye gerek olmadığını unutmayın: sabitleri olan bazı sorguların olması son derece uygundur ve aslında veritabanları (ve EF) bazen sorgu parametrelendirildiğinde mümkün olmayan sabitler etrafında belirli iyileştirmeler gerçekleştirebilir. Düzgün parametreleştirmenin kritik öneme sahip olduğu bir örnek için dinamik olarak derlenmiş sorgular bölümüne bakın.

Not

EF Core'un ölçümleri Sorgu Önbelleği İsabet Oranını bildirir. Normal bir uygulamada, çoğu sorgu en az bir kez yürütüldükten sonra bu ölçüm program başlangıcından hemen sonra %100'e ulaşır. Bu ölçüm %100'ün altında kararlı kalırsa bu, uygulamanızın sorgu önbelleğini yenen bir şey yapıyor olabileceğinin bir göstergesidir. Bunu araştırmak iyi bir fikirdir.

Not

Veritabanının önbellek sorgu planlarını yönetme şekli veritabanına bağlıdır. Örneğin, SQL Server örtük olarak bir LRU sorgu planı önbelleği tutarken PostgreSQL bunu yapmaz (ancak hazırlanan deyimler çok benzer bir son etki oluşturabilir). Daha fazla ayrıntı için veritabanı belgelerinize bakın.

Dinamik olarak derlenmiş sorgular

Bazı durumlarda, LINQ sorgularını kaynak kodda tam olarak belirtmek yerine dinamik olarak oluşturmak gerekir. Örneğin, açık uçlu sorgu işleçleriyle (sıralama, filtreleme, sayfalama...) istemciden rastgele sorgu ayrıntıları alan bir web sitesinde bu durum oluşabilir. Prensipte, doğru yapılırsa, dinamik olarak yapılandırılmış sorgular normal sorgular kadar verimli olabilir (ancak derlenmiş sorgu iyileştirmesini dinamik sorgularla kullanmak mümkün değildir). Ancak uygulamada, genellikle performans sorunlarının kaynağıdır, çünkü her seferinde farklı şekillere sahip ifade ağaçlarını yanlışlıkla üretmek kolaydır.

Aşağıdaki örnekte, sorgunun Where lambda ifadesini oluşturmak için üç teknik kullanılır:

  1. Sabit olan ifade API'si: İfade API'siyle ifadeyi dinamik olarak, sabit bir düğüm kullanarak oluşturun. Bu, ifade ağaçlarını dinamik olarak oluştururken sık yapılan bir hatadır ve EF'nin farklı bir sabit değerle her çağrıldığında sorguyu yeniden derlemesine neden olur (genellikle veritabanı sunucusunda plan önbelleği kirliliğine de neden olur).
  2. Parametresi olan ifade API'si: Sabiti bir parametreyle değiştiren daha iyi bir sürüm. Bu, sorgunun sağlanan değerden bağımsız olarak yalnızca bir kez derlendiğinden ve aynı (parametreli) SQL'in oluşturulmasından emin olur.
  3. Parametresiyle basit: Karşılaştırma için İfade API'sini kullanmayan ve yukarıdaki yöntemle aynı ağacı oluşturan ancak çok daha basit olan bir sürüm. Çoğu durumda İfade API'sine başvurmadan ifade ağacınızı dinamik olarak oluşturmak mümkündür ve bu da kolayca yanlış anlaşılır.

Sorguya yalnızca verilen parametre null değilse bir Where işleç ekleriz. Bunun bir sorguyu dinamik olarak oluşturmak için iyi bir kullanım örneği olmadığını, ancak basitlik için kullandığımızı unutmayın:

[Benchmark]
public int ExpressionApiWithConstant()
{
    var url = "blog" + Interlocked.Increment(ref _blogNumber);
    using var context = new BloggingContext();

    IQueryable<Blog> query = context.Blogs;

    if (_addWhereClause)
    {
        var blogParam = Expression.Parameter(typeof(Blog), "b");
        var whereLambda = Expression.Lambda<Func<Blog, bool>>(
            Expression.Equal(
                Expression.MakeMemberAccess(
                    blogParam,
                    typeof(Blog).GetMember(nameof(Blog.Url)).Single()),
                Expression.Constant(url)),
            blogParam);

        query = query.Where(whereLambda);
    }

    return query.Count();
}

Bu iki tekniğin karşılaştırması aşağıdaki sonuçları verir:

Metot Ortalama Hata StdDev 0. Nesil 1. Nesil Tahsis edilen
ExpressionApiWithConstant 1,665,8 bize 56.99 bize 163.5 biz 15.6250 - 109,92 KB
ExpressionApiWithParameter 757.1 biz 35.14 bize 103.6 bize 12.6953 0.9766 54,95 KB
SimpleWithParameter 760.3 bize 37.99 bize 112.0 bize 12.6953 - 55,03 KB

Milisaniyenin altındaki fark küçük görünse bile, sabit sürümün önbelleği sürekli olarak kirlettiğine ve diğer sorguların yeniden derlenmesine neden olduğunu, bunları yavaşlattığını ve genel performansınızı genel olarak olumsuz etkilediğini unutmayın. Sabit sorgu yeniden derlemesini önlemek kesinlikle önerilir.

Not

Gerçekten gerekmedikçe ifade ağacı API'si ile sorgu oluşturmaktan kaçının. API'nin karmaşıklığının yanı sıra, bunları kullanırken yanlışlıkla önemli performans sorunlarına neden olmak çok kolaydır.

Derlenmiş modeller

Derlenmiş modeller, büyük modellere sahip uygulamalar için EF Core başlangıç süresini iyileştirebilir. Büyük bir model genellikle yüz binlerce varlık türü ve ilişkisi anlamına gelir. Burada başlangıç zamanı, uygulamada ilk kez bu tür kullanıldığında ilk işlemi DbContextDbContext gerçekleştirme zamanıdır. Yalnızca örnek DbContext oluşturmanın EF modelinin başlatılmasına neden olmadığını unutmayın. Bunun yerine, modelin başlatılmasına neden olan tipik ilk işlemler ilk sorguyu çağırmak DbContext.Add veya yürütmektir.

Derlenen modeller komut satırı aracı kullanılarak dotnet ef oluşturulur. Devam etmeden önce aracın en son sürümünü yüklediğinizden emin olun.

Derlenmiş modeli oluşturmak için yeni dbcontext optimize bir komut kullanılır. Örneğin:

dotnet ef dbcontext optimize

--output-dir ve --namespace seçenekleri, derlenen modelin oluşturulacağı dizini ve ad alanını belirtmek için kullanılabilir. Örneğin:

PS C:\dotnet\efdocs\samples\core\Miscellaneous\CompiledModels> dotnet ef dbcontext optimize --output-dir MyCompiledModels --namespace MyCompiledModels
Build started...
Build succeeded.
Successfully generated a compiled model, to use it call 'options.UseModel(MyCompiledModels.BlogsContextModel.Instance)'. Run this command again when the model is modified.
PS C:\dotnet\efdocs\samples\core\Miscellaneous\CompiledModels>
  • Daha fazla bilgi için bkz. dotnet ef dbcontext optimize.
  • Visual Studio'da daha rahat çalışıyorsanız Optimize-DbContext özelliğini de kullanabilirsiniz

Bu komutun çalıştırılmasından elde edilen çıkış, EF Core'un derlenmiş modeli kullanmasına neden olmak için yapılandırmanıza DbContext kopyalayıp yapıştıracak bir kod parçası içerir. Örneğin:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseModel(MyCompiledModels.BlogsContextModel.Instance)
        .UseSqlite(@"Data Source=test.db");

Derlenmiş model önyüklemesi

Genellikle oluşturulan önyükleme koduna bakmak gerekmez. Ancak bazen modeli veya yüklemesini özelleştirmek yararlı olabilir. Bootstrapping kodu şuna benzer:

[DbContext(typeof(BlogsContext))]
partial class BlogsContextModel : RuntimeModel
{
    private static BlogsContextModel _instance;
    public static IModel Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new BlogsContextModel();
                _instance.Initialize();
                _instance.Customize();
            }

            return _instance;
        }
    }

    partial void Initialize();

    partial void Customize();
}

Bu, modeli gerektiği gibi özelleştirmek için uygulanabilen kısmi yöntemlere sahip kısmi bir sınıftır.

Ayrıca, bazı çalışma zamanı yapılandırmasına bağlı olarak farklı modeller kullanabilecek türler için DbContext birden çok derlenmiş model oluşturulabilir. Bunlar, yukarıda gösterildiği gibi farklı klasörlere ve ad alanlarına yerleştirilmelidir. Daha sonra bağlantı dizesi gibi çalışma zamanı bilgileri incelenebilir ve gerektiğinde doğru model döndürülebilir. Örneğin:

public static class RuntimeModelCache
{
    private static readonly ConcurrentDictionary<string, IModel> _runtimeModels
        = new();

    public static IModel GetOrCreateModel(string connectionString)
        => _runtimeModels.GetOrAdd(
            connectionString, cs =>
            {
                if (cs.Contains("X"))
                {
                    return BlogsContextModel1.Instance;
                }

                if (cs.Contains("Y"))
                {
                    return BlogsContextModel2.Instance;
                }

                throw new InvalidOperationException("No appropriate compiled model found.");
            });
}

Sınırlamalar

Derlenen modellerin bazı sınırlamaları vardır:

Bu sınırlamalar nedeniyle, derlenmiş modelleri yalnızca EF Core başlangıç süreniz çok yavaşsa kullanmanız gerekir. Küçük modelleri derlemek genellikle buna değmez.

Bu özelliklerden herhangi birinin desteklenmesi başarınız için kritik önem taşıyorsa lütfen yukarıda belirtilen uygun sorunlar için oy verin.

Çalışma zamanı ek yükünü azaltma

Her katmanda olduğu gibi EF Core da doğrudan alt düzey veritabanı API'lerine karşı kodlamaya kıyasla biraz çalışma zamanı yükü ekler. Bu çalışma zamanı ek yükünün gerçek dünya uygulamalarının çoğunu önemli ölçüde etkileme olasılığı düşüktür; bu performans kılavuzundaki sorgu verimliliği, dizin kullanımı ve gidiş dönüşleri en aza indirme gibi diğer konular çok daha önemlidir. Buna ek olarak, yüksek oranda iyileştirilmiş uygulamalar için bile ağ gecikme süresi ve veritabanı G/Ç genellikle EF Core'un içinde harcanan her zamana hakim olur. Ancak, her performans bitinin önemli olduğu yüksek performanslı, düşük gecikme süreli uygulamalarda EF Core ek yükünü en aza indirgemek için aşağıdaki öneriler kullanılabilir:

  • DbContext havuzunu açın; karşılaştırmalarımız bu özelliğin yüksek performans ve düşük gecikme süresine sahip uygulamalar üzerinde belirleyici bir etkiye sahip olabileceğini gösteriyor.
    • öğesinin maxPoolSize kullanım senaryonuza karşılık olduğundan emin olun; çok düşükse örnekler DbContext sürekli oluşturulur ve atılır ve performansı düşürür. Çok yüksek olarak ayarlamak, kullanılmayan DbContext örnekler havuzda tutuldukçe gereksiz bir şekilde bellek tüketebilir.
    • Ek küçük performans artışı için DOĞRUDAN DI ekleme bağlam örneklerini kullanmak yerine kullanmayı PooledDbContextFactory göz önünde bulundurun. Havuz oluşturmanın DbContext DI yönetimi hafif bir yüke neden olabilir.
  • Sık erişimli sorgular için önceden derlenmiş sorgular kullanın.
    • LINQ sorgusu ne kadar karmaşıksa ve ne kadar çok işleç içeriyorsa ve sonuçta elde edilen ifade ağacı o kadar büyükse, derlenmiş sorguların kullanılmasından o kadar fazla kazanç beklenebilir.
  • Bağlam yapılandırmanızda false olarak ayarlayarak EnableThreadSafetyChecks iş parçacığı güvenliği denetimlerini devre dışı bırakmayı göz önünde bulundurun.
    • Aynı DbContext örneğin farklı iş parçacıklarından eşzamanlı olarak kullanılması desteklenmez. EF Core' un çoğu durumda (tümü değil) bu programlama hatalarını algılayan ve hemen bilgilendirici bir özel durum oluşturan bir güvenlik özelliği vardır. Ancak, bu güvenlik özelliği çalışma zamanı ek yükü ekler.
    • UYARI: Yalnızca uygulamanızın bu tür eşzamanlılık hataları içermediğini kapsamlı bir şekilde test ettikten sonra iş parçacığı güvenliği denetimlerini devre dışı bırakın.