Mempercepat Inti Kerangka Entitas

Jangan serakah!


Saat memilih data, Anda harus memilih sebanyak yang Anda butuhkan pada suatu waktu. Jangan pernah mengambil semua data dari tabel!

Salah:

using var ctx = new EFCoreTestContext(optionsBuilder.Options);                
//    ID  ,       !
ctx.FederalDistricts.Select(x=> new { x.ID, x.Name, x.ShortName }).ToList();

Benar:

using var ctx = new EFCoreTestContext(optionsBuilder.Options);  
//     ID     !
ctx.FederalDistricts.Select(x=> new { x.Name, x.ShortName }).ToList();
ctx.FederalDistricts.Select(x => new MyClass { Name = x.Name, ShortName = x.ShortName }).ToList();


Salah:

var blogs = context.Blog.ToList(); //       . ?
//     ?
var somePost = blogs.FirstOrDefault(x=>x.Title.StartWidth(“Hello world!”));

Benar:

var somePost = context.Blog.FirstOrDefault(x=>x.Title.StartWidth(“Hello world!”));

Validasi data terintegrasi dapat dilakukan ketika kueri mengembalikan beberapa catatan.

Salah:


var blogs = context.Blogs.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet")).ToList();

public static string StandardizeUrl(string url)
{
    url = url.ToLower();
    if (!url.StartsWith("http://"))
    {
        url = string.Concat("http://", url);
    }
    return url;
}

Benar:

var blogs = context.Blogs.AsEnumerable().Where(blog => StandardizeUrl(blog.Url).Contains("dotnet")).ToList();
 
//  
var blogs = context.Blogs.Where(blog => blog.Contains("dotnet"))
    .OrderByDescending(blog => blog.Rating)
    .Select(blog => new
    {
        Id = blog.BlogId,
        Url = StandardizeUrl(blog.Url)
    })
    .ToList();

Wow, wow, wow, sampai.

Saatnya menyegarkan sedikit pengetahuan Anda tentang teknik LINQ.

Mari kita lihat perbedaan antara ToList AsEnumerable AsQueryable


jadi ToList

  • .
  • .ToList() (lazy loading), .

AsEnumerable

  • (lazy loading)
  • : Func <TSource, bool>
  • ( Where/Take/Skip , , select * from Table1,
  • , N )
  • : Linq-to-SQL + Linq-to-Object.
  • IEnumerable (lazy loading).

AsQueryable

  • (lazy loading)
  • :
    AsQueryable(IEnumerable)  AsQueryable<TElement>(IEnumerable<TElement>) 

  • Expression T-SQL ( ), .
  • DbSet ( Entity Framework) AsQueryable .
  • , Take(5) «select top 5 * SQL» . , SQL , . AsQueryable() , AsEnumerable() T-SQL Linq .
  • Gunakan AsQueryable jika Anda ingin kueri basis data yang dapat ditingkatkan sebelum berjalan di sisi server.


Contoh menggunakan AsQueryable dalam kasus paling sederhana:

public IEnumerable<EmailView> GetEmails(out int totalRecords, Guid? deviceWorkGroupID,
                DateTime? timeStart, DateTime? timeEnd, string search, int? confirmStateID, int? stateTypeID, int? limitOffset, int? limitRowCount, string orderBy, bool desc)
        {
            var r = new List<EmailView>();

            using (var db = new GJobEntities())
            {
                var query = db.Emails.AsQueryable();

                if (timeStart != null && timeEnd != null)
                {
                    query = query.Where(p => p.Created >= timeStart && p.Created <= timeEnd);
                }

                if (stateTypeID != null && stateTypeID > -1)
                {
                    query = query.Where(p => p.EmailStates.OrderByDescending(x => x.AtTime).FirstOrDefault().EmailStateTypeID == stateTypeID);
                }


                if (confirmStateID != null && confirmStateID > -1)
                {
                    var boolValue = confirmStateID == 1 ? true : false;
                    query = query.Where(p => p.IsConfirmed == boolValue);
                }

                if (!string.IsNullOrEmpty(search))
                {
                    search = search.ToLower();
                    query = query.Where(p => (p.Subject + " " + p.CopiesEmails + " " + p.ToEmails + " " + p.FromEmail + " " + p.Body)
                                        .ToLower().Contains(search));
                }

                if (deviceWorkGroupID != Guid.Empty)
                {
                    query = query.Where(x => x.SCEmails.FirstOrDefault().SupportCall.Device.DeviceWorkGroupDevices.FirstOrDefault(p => p.DeviceWorkGroupID == deviceWorkGroupID) != null);
                }

                totalRecords = query.Count();
                query = query.OrderByDescending(p => p.Created);
                if (limitOffset.HasValue)
                {
                    query = query.Skip(limitOffset.Value).Take(limitRowCount.Value);
                }
                var items = query.ToList(); //    

                foreach (var item in items)
                {
                    var n = new EmailView
                    {
                        ID = item.ID,
                        SentTime = item.SentTime,
                        IsConfirmed = item.IsConfirmed,
                        Number = item.Number,
                        Subject = item.Subject,
                        IsDeleted = item.IsDeleted,
                        ToEmails = item.ToEmails,
                        Created = item.Created,
                        CopiesEmails = item.CopiesEmails,
                        FromEmail = item.FromEmail,
                    };

                    //     - 

                    r.Add(n);
                }
            }

            return r;
        }


Keajaiban membaca sederhana


Jika Anda tidak perlu mengubah data, cukup tampilkan menggunakan metode .AsNoTracking () .

Pengambilan sampel lambat

var blogs = context.Blogs.ToList();

Ambil cepat (hanya baca)

var blogs = context.Blogs.AsNoTracking().ToList();

Merasa sudah sedikit pemanasan?

Jenis memuat data terkait


Bagi mereka yang lupa apa itu pemuatan malas .

Pemuatan malas (Lazy loading) berarti bahwa data terkait secara transparan dimuat dari database ketika mengakses properti navigasi. Baca lebih lanjut di sini .

Dan pada saat yang sama, izinkan saya mengingatkan Anda tentang jenis pemuatan data terkait lainnya.

Beban aktif (Eager loading) berarti bahwa data terkait dimuat dari database sebagai bagian dari permintaan awal.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
                .ThenInclude(author => author.Photo)
        .Include(blog => blog.Owner)
            .ThenInclude(owner => owner.Photo)
        .ToList();
}

Perhatian! Dimulai dengan versi EF Core 3.0.0, setiap Include akan menyebabkan JOIN tambahan ditambahkan ke query SQL yang dihasilkan oleh penyedia relasional, sementara versi sebelumnya menghasilkan query SQL tambahan. Ini secara signifikan dapat mengubah kinerja kueri Anda, menjadi lebih baik atau lebih buruk. Secara khusus, kueri LINQ dengan sejumlah besar pernyataan inklusi dapat dibagi menjadi beberapa kueri LINQ yang terpisah.

Pembebanan eksplisit (Explicit loading) berarti bahwa data terkait secara eksplisit diambil dari basis data nanti.

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Single(b => b.BlogId == 1);

    var goodPosts = context.Entry(blog)
        .Collection(b => b.Posts)
        .Query()
        .Where(p => p.Rating > 3)
        .ToList();
}

Brengsek dan terobosan! Bergerak?

Siap untuk mempercepat bahkan lebih?


Untuk mempercepat secara dramatis ketika mengambil data yang terstruktur dengan rumit dan bahkan tidak normal dari database relasional, ada dua cara untuk melakukan ini: gunakan tampilan yang diindeks (1) atau, lebih baik lagi, data yang telah disiapkan sebelumnya (dihitung) dalam bentuk datar sederhana untuk tampilan (2).

(1) Tampilan diindeks dalam konteks MS SQL Server

Tampilan yang diindeks memiliki indeks berkerumun yang unik. Indeks berkerumun unik disimpan di SQL Server dan diperbarui seperti indeks berkerumun lainnya. Tampilan yang diindeks lebih penting daripada tampilan standar, yang mencakup pemrosesan kompleks sejumlah besar baris, misalnya, menggabungkan sejumlah besar data atau menggabungkan beberapa baris.

Jika tampilan seperti itu sering direferensikan dalam kueri, kami dapat meningkatkan kinerja dengan membuat indeks clustered unik untuk tampilan. Untuk tampilan standar, set hasil tidak disimpan dalam database, sebagai gantinya, set hasil dihitung untuk setiap permintaan, tetapi dalam kasus indeks berkerumun, set hasil disimpan dalam database dengan cara yang sama seperti tabel dengan indeks berkerumun. Kueri yang tidak secara khusus menggunakan tampilan yang diindeks mungkin bahkan mendapat manfaat dari keberadaan indeks yang dikelompokkan dari tampilan.

Representasi suatu indeks memiliki biaya tertentu dalam bentuk produktivitas. Jika kita membuat tampilan yang diindeks, setiap kali kita mengubah data dalam tabel dasar, SQL Server harus mendukung tidak hanya catatan indeks dalam tabel ini, tetapi juga catatan indeks dalam tampilan. Dalam edisi SQL Server untuk pengembang dan perusahaan, pengoptimal dapat menggunakan indeks tampilan untuk mengoptimalkan kueri yang tidak menentukan tampilan yang diindeks. Namun, di edisi lain dari SQL Server, kueri harus menyertakan tampilan yang diindeks dan memberikan petunjuk NOEXPAND untuk memanfaatkan indeks dalam tampilan.

(2) Jika Anda perlu membuat permintaan yang memerlukan tampilan lebih dari tiga tingkat tabel terkait dalam jumlah tiga atau lebih dengan peningkatan CRUDmemuat, cara terbaik adalah menghitung set hasil secara berkala, menyimpannya dalam tabel dan digunakan untuk tampilan. Tabel yang dihasilkan di mana data akan disimpan harus memiliki Kunci Utama dan indeks pada bidang pencarian di LINQ .

Bagaimana dengan asinkron?


Iya! Kami menggunakannya sedapat mungkin! Berikut ini sebuah contoh:

public void Do()
{
    var myTask = GetFederalDistrictsAsync ();
    foreach (var item in myTask.Result)
    {
         // 
    }
}

public async Task<List<FederalDistrict>> GetFederalDistrictsAsync()
{
    var conn = configurationRoot.GetConnectionString("EFCoreTestContext");
    optionsBuilder.UseSqlServer(conn);
    using var context = new EFCoreTestContext(optionsBuilder.Options);
    return await context.FederalDistricts.ToListAsync();
}

Dan ya, apakah Anda lupa sesuatu untuk meningkatkan produktivitas? Buum!

return await context.FederalDistricts.<b>AsNoTracking()</b>.ToListAsync();


Catatan: metode Do () ditambahkan hanya untuk tujuan demonstrasi, untuk menunjukkan operabilitas dari metode GetFederalDistrictsAsync () . Seperti yang dicatat oleh rekan-rekan saya dengan benar, diperlukan contoh asynchrony murni lainnya.

Dan izinkan saya memberikannya berdasarkan konsep komponen tampilan di ASP .NET Core :

//  
public class PopularPosts : ViewComponent
    {
        private readonly IStatsRepository _statsRepository;

        public PopularPosts(IStatsRepository statsRepository)
        {
            _statsRepository = statsRepository;
        }

        public async Task<IViewComponentResult> InvokeAsync()
        {
           //         -
            var federalDistricts = await _statsRepository.GetFederalDistrictsAsync(); 
            var model = new TablePageModel()
            {
                FederalDistricts = federalDistricts,
            };

            return View(model);
        }
    }
    // 
    
    /// <summary>
    ///  -   .... -
    /// </summary>
    public interface IStatsRepository
    {
        /// <summary>
        ///        
        /// </summary>
        /// <returns></returns>
        IEnumerable<FederalDistrict> FederalDistricts();

        /// <summary>
        ///        
	/// !!!
        /// </summary>
        /// <returns></returns>
        Task<List<FederalDistrict>> GetFederalDistrictsAsync();
    }	
	
    /// <summary>
    /// -   .... -
    /// </summary>
    public class StatsRepository : IStatsRepository
    {
        private readonly DbContextOptionsBuilder<EFCoreTestContext>
            optionsBuilder = new DbContextOptionsBuilder<EFCoreTestContext>();
        private readonly IConfigurationRoot configurationRoot;

        public StatsRepository()
        {
            IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
                    .SetBasePath(Environment.CurrentDirectory)
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
            configurationRoot = configurationBuilder.Build();
        }

        public async Task<List<FederalDistrict>> GetFederalDistrictsAsync()
        {
            var conn = configurationRoot.GetConnectionString("EFCoreTestContext");
            optionsBuilder.UseSqlServer(conn);
            using var context = new EFCoreTestContext(optionsBuilder.Options);
            return await context.FederalDistricts.Include(x => x.FederalSubjects).ToListAsync();
        }

        public IEnumerable<FederalDistrict> FederalDistricts()
        {
            var conn = configurationRoot.GetConnectionString("EFCoreTestContext");
            optionsBuilder.UseSqlServer(conn);

            using var ctx = new EFCoreTestContext(optionsBuilder.Options);
            return ctx.FederalDistricts.Include(x => x.FederalSubjects).ToList();
        }
    }

   //         Home\Index 
    <div id="tableContainer">
            @await Component.InvokeAsync("PopularPosts")
     </div>
  //   HTML      Shared\Components\PopularPosts\Default.cshtml



Biarkan saya mengingatkan Anda ketika kueri dieksekusi di Entity Framework Core.

Saat memanggil pernyataan LINQ, Anda cukup membuat tampilan kueri di memori. Permintaan dikirim ke database hanya setelah memproses hasilnya.

Berikut ini adalah operasi paling umum yang menghasilkan permintaan dikirim ke database.

  • Iterate atas hasil dalam for for loop.
  • Menggunakan operator, seperti ToList, ToArray, Single, Count.
  • Mengikat data dari hasil kueri ke antarmuka pengguna.

Bagaimana cara mengatur kode EF Core dalam hal arsitektur aplikasi?


(1) Dari sudut pandang arsitektur aplikasi, Anda perlu memastikan bahwa kode akses ke basis data Anda diisolasi / dipisahkan di tempat yang jelas (terpisah). Ini memungkinkan Anda menemukan kode basis data yang memengaruhi kinerja.

(2) Jangan mencampur kode akses untuk database Anda dengan bagian lain dari aplikasi, seperti antarmuka pengguna atau API. Dengan demikian, kode akses database dapat diubah tanpa khawatir tentang masalah lain yang tidak terkait dengan database.

Bagaimana cara menyimpan data dengan benar dan cepat menggunakan SaveChanges ?


Jika catatan yang dimasukkan adalah sama, masuk akal untuk menggunakan operasi satu penyimpanan untuk semua catatan.

Salah

using(var db = new NorthwindEntities())
{
var transaction = db.Database.BeginTransaction();

try
{
    //   1
    var  obj1 = new Customer();
    obj1.CustomerID = "ABCDE";
    obj1.CompanyName = "Company 1";
    obj1.Country = "USA";
    db.Customers.Add(obj1);

  //          db.SaveChanges();

    //   2
    var  obj2 = new Customer();
    obj2.CustomerID = "PQRST";
    obj2.CompanyName = "Company 2";    
    obj2.Country = "USA";
    db.Customers.Add(obj2);

    //   
    db.SaveChanges();

    transaction.Commit();
}
catch
{
    transaction.Rollback();
}
}

Benar

using(var db = new NorthwindEntities())
{
var transaction = db.Database.BeginTransaction();

try
{
   //  1
    var  obj1 = new Customer();
    obj1.CustomerID = "ABCDE";
    obj1.CompanyName = "Company 1";
    obj1.Country = "USA";
    db.Customers.Add(obj1); 

    //   2
    var  obj2 = new Customer();
    obj2.CustomerID = "PQRST";
    obj2.CompanyName = "Company 2";    
    obj2.Country = "USA";
    db.Customers.Add(obj2);

   //    N 
    db.SaveChanges();

    transaction.Commit();
}
catch
{
    transaction.Rollback();
}
}

Selalu ada pengecualian untuk aturan tersebut. Jika konteks transaksi kompleks, yaitu terdiri dari beberapa operasi independen, maka Anda dapat menyimpan setelah setiap operasi. Dan bahkan lebih benar untuk menggunakan penyimpanan asinkron dalam suatu transaksi.

//    
public async Task<IActionResult> AddDepositToHousehold(int householdId, DepositRequestModel model)
{
    using (var transaction = await Context.Database.BeginTransactionAsync(IsolationLevel.Snapshot))
    {
        try
        {
            //     
            var deposit = this.Mapper.Map<Deposit>(model);
            await this.Context.Deposits.AddAsync(deposit);

            await this.Context.SaveChangesAsync();

            //    
               var debtsToPay = await this.Context.Debts.Where(d => d.HouseholdId == householdId && !d.IsPaid).OrderBy(d => d.DateMade).ToListAsync();

            debtsToPay.ForEach(d => d.IsPaid = true);

            await this.Context.SaveChangesAsync();

            //   
            var household = this.Context.Households.FirstOrDefaultAsync(h => h.Id == householdId);

            household.Balance += model.DepositAmount;

            await this.Context.SaveChangesAsync();

            transaction.Commit();
            return this.Ok();
        }
        catch
        {
            transaction.Rollback();
            return this.BadRequest();
        }
    }
}

Pemicu, Bidang Komputer, Fungsi Kustom, dan EF Core


Untuk mengurangi beban pada aplikasi yang mengandung EF Core, masuk akal untuk menggunakan bidang terhitung sederhana dan pemicu basis data, tetapi lebih baik untuk tidak terlibat, karena aplikasi bisa sangat membingungkan. Tetapi fungsi yang ditentukan pengguna bisa sangat berguna terutama selama operasi pengambilan!

Konkurensi dalam EF Core


Jika Anda ingin memparalelkan semuanya untuk mempercepat, maka putus: EF Core tidak mendukung pelaksanaan beberapa operasi paralel dalam satu contoh konteks. Tunggu satu operasi selesai sebelum memulai yang berikutnya. Untuk melakukan ini, Anda biasanya perlu menentukan kata kunci tunggu di setiap operasi asinkron.

EF Core menggunakan kueri asinkron untuk menghindari memblokir aliran ketika mengeksekusi kueri dalam database. Permintaan asinkron penting untuk memastikan respons antarmuka pengguna yang cepat pada klien yang tebal. Mereka juga dapat meningkatkan throughput dalam aplikasi web, di mana Anda dapat membebaskan utas untuk menangani permintaan lainnya. Berikut ini sebuah contoh:

public async Task<List<Blog>> GetBlogsAsync()
{
    using (var context = new BloggingContext())
    {
        return await context.Blogs.ToListAsync();
    }
}

Apa yang Anda ketahui tentang kueri yang dikompilasi LINQ?


Jika Anda memiliki aplikasi yang berulang kali melakukan kueri yang serupa secara struktural dalam Entity Framework, Anda seringkali dapat meningkatkan kinerja dengan mengkompilasi kueri sekali dan menjalankannya beberapa kali dengan parameter yang berbeda. Misalnya, aplikasi mungkin perlu untuk mendapatkan semua pelanggan di kota tertentu; kota ditunjukkan saat runtime oleh pengguna dalam formulir. LINQ to Entities mendukung penggunaan kueri yang dikompilasi untuk tujuan ini.

Dimulai dengan .NET Framework 4.5, kueri LINQ di-cache secara otomatis. Namun, Anda masih bisa menggunakan kueri LINQ yang dikompilasi untuk mengurangi biaya ini dalam menjalankan selanjutnya, dan kueri yang dikompilasi bisa lebih efisien daripada kueri LINQ yang di-cache secara otomatis. Perhatikan bahwa kueri LINQ ke Entitas yang menerapkan operator Enumerable.Contains ke koleksi dalam memori tidak di-cache secara otomatis. Juga, parameterisasi koleksi di dalam memori dalam kueri LINQ yang dikompilasi tidak diperbolehkan.

Banyak contoh dapat ditemukan di sini .

Jangan membuat konteks DbContext yang besar!


Secara umum, saya tahu banyak dari Anda, jika tidak hampir semua, f_u__c_k__e_r__s malas dan seluruh database, Anda menempatkan dalam satu konteks, ini terutama berlaku untuk pendekatan Database-First. Dan sia-sia Anda melakukannya! Berikut ini adalah contoh bagaimana konteksnya dapat dibagi. Tentu saja, tabel koneksi antar konteks harus diduplikasi, ini minus. Dengan satu atau lain cara, jika Anda memiliki lebih dari 50 tabel dalam konteks, lebih baik untuk berpikir tentang membaginya.

Menggunakan pengelompokan konteks (pooling DdContext)


Arti kumpulan DbContext adalah untuk memungkinkan penggunaan kembali contoh DbContext dari kumpulan, yang dalam beberapa kasus dapat menyebabkan kinerja yang lebih baik daripada membuat contoh baru setiap kali. Ini juga merupakan alasan utama untuk membuat kumpulan koneksi di ADO.NET, meskipun peningkatan kinerja untuk koneksi akan lebih signifikan karena koneksi umumnya merupakan sumber yang lebih sulit.

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace Demos
{
    public class Blog
    {
        public int BlogId { get; set; }
        public string Name { get; set; }
        public string Url { get; set; }
    }

    public class BloggingContext : DbContext
    {
        public static long InstanceCount;

        public BloggingContext(DbContextOptions options)
            : base(options)
            => Interlocked.Increment(ref InstanceCount);

        public DbSet<Blog> Blogs { get; set; }
    }

    public class BlogController
    {
        private readonly BloggingContext _context;

        public BlogController(BloggingContext context) => _context = context;

        public async Task ActionAsync() => await _context.Blogs.FirstAsync();
    }

    public class Startup
    {
        private const string ConnectionString
            = @"Server=(localdb)\mssqllocaldb;Database=Demo.ContextPooling;Integrated Security=True;ConnectRetryCount=0";

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<BloggingContext>(c => c.UseSqlServer(ConnectionString));
        }
    }

    public class Program
    {
        private const int Threads = 32;
        private const int Seconds = 10;

        private static long _requestsProcessed;

        private static async Task Main()
        {
            var serviceCollection = new ServiceCollection();
            new Startup().ConfigureServices(serviceCollection);
            var serviceProvider = serviceCollection.BuildServiceProvider();

            SetupDatabase(serviceProvider);

            var stopwatch = new Stopwatch();

            MonitorResults(TimeSpan.FromSeconds(Seconds), stopwatch);

            await Task.WhenAll(
                Enumerable
                    .Range(0, Threads)
                    .Select(_ => SimulateRequestsAsync(serviceProvider, stopwatch)));
        }

        private static void SetupDatabase(IServiceProvider serviceProvider)
        {
            using (var serviceScope = serviceProvider.CreateScope())
            {
                var context = serviceScope.ServiceProvider.GetService<BloggingContext>();

                if (context.Database.EnsureCreated())
                {
                    context.Blogs.Add(new Blog { Name = "The Dog Blog", Url = "http://sample.com/dogs" });
                    context.Blogs.Add(new Blog { Name = "The Cat Blog", Url = "http://sample.com/cats" });
                    context.SaveChanges();
                }
            }
        }
        private static async Task SimulateRequestsAsync(IServiceProvider serviceProvider, Stopwatch stopwatch)
        {
            while (stopwatch.IsRunning)
            {
                using (var serviceScope = serviceProvider.CreateScope())
                {
                    await new BlogController(serviceScope.ServiceProvider.GetService<BloggingContext>()).ActionAsync();
                }

                Interlocked.Increment(ref _requestsProcessed);
            }
        }

        private static async void MonitorResults(TimeSpan duration, Stopwatch stopwatch)
        {
            var lastInstanceCount = 0L;
            var lastRequestCount = 0L;
            var lastElapsed = TimeSpan.Zero;

            stopwatch.Start();

            while (stopwatch.Elapsed < duration)
            {
                await Task.Delay(TimeSpan.FromSeconds(1));

                var instanceCount = BloggingContext.InstanceCount;
                var requestCount = _requestsProcessed;
                var elapsed = stopwatch.Elapsed;
                var currentElapsed = elapsed - lastElapsed;
                var currentRequests = requestCount - lastRequestCount;

                Console.WriteLine(
                    $"[{DateTime.Now:HH:mm:ss.fff}] "
                    + $"Context creations/second: {instanceCount - lastInstanceCount} | "
                    + $"Requests/second: {Math.Round(currentRequests / currentElapsed.TotalSeconds)}");

                lastInstanceCount = instanceCount;
                lastRequestCount = requestCount;
                lastElapsed = elapsed;
            }

            Console.WriteLine();
            Console.WriteLine($"Total context creations: {BloggingContext.InstanceCount}");
            Console.WriteLine(
                $"Requests per second:     {Math.Round(_requestsProcessed / stopwatch.Elapsed.TotalSeconds)}");

            stopwatch.Stop();
        }

Bagaimana cara menghindari kesalahan yang tidak perlu dengan CRUD di EF Core?


Jangan pernah memasukkan perhitungan dalam kode yang sama. Selalu pisahkan pembentukan / persiapan suatu objek dan penyisipan / pembaruannya. Sebarkan saja dengan fungsi: memeriksa data yang dimasukkan oleh pengguna, menghitung data awal yang diperlukan, memetakan atau membuat objek, dan operasi CRUD yang sebenarnya.

Apa yang harus dilakukan ketika segalanya benar-benar buruk dengan kinerja aplikasi?


Bir pasti tidak akan membantu di sini. Tetapi yang akan membantu adalah pemisahan antara membaca dan menulis dalam arsitektur aplikasi, diikuti oleh alokasi operasi ini pada soket. Pikirkan tentang menggunakan pola Command and Query Responsibility Segregation (CQRS) , dan juga coba pisahkan tabel menjadi insert dan baca di antara dua database.

Mempercepat aplikasi untuk Anda, teman, dan kolega!

Source: https://habr.com/ru/post/undefined/


All Articles