Skip to content

EF Core - Memory and performance issues with async methods #21147

@DanielO398

Description

@DanielO398

Yesterday I created a issue in EF6 about a performance issue the company I work for have. We have an old legacy system are putting binary data into the SQL Server. Our new .NET server needs to use this data in some cases and this causes one of our customers to have their server freezing up to 20 minutes when is busy.

I am unsure what the procedure is for issues found in both frameworks. Because the reason I actually found it was to see if it was a possible workaround for us. However is not a viable solution as it will take a lot longer than a weekend to re-write from EF6 to EF Core and the same issue is found in EF Core.

Another discovery I made is that the memory issue is a lot worse in EF Core.

Steps to reproduce

You can find my repository where i recreated the issue from production in a dummy project for both EF Core and EF6. Repo link

Or find the code below for EF Core

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

namespace PerformanceIssueEFCoreAsync
{
  public class Item
  {
    public int Id { get; set; }
    public byte[] Data { get; set; }
  }
  public class ItemContext : DbContext
  {
    public DbSet<Item> Items { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      optionsBuilder.UseSqlServer(
@"Data Source=localhost;Initial Catalog=ItemDb;Integrated Security=true;");
    }
  }
  internal class Program
  {
    private static async Task Main(string[] args)
    {
      Console.WriteLine("Ready to consume a lot of memory with EF.");

      using (var db = new ItemContext())
      {
        db.Database.EnsureCreated();

        //insert dummy record
        if (db.Items.ToArray().Length == 0)
        {
          db.Items.Add(new Item { Data = new byte[2 * 1024 * 1024] });
          db.Items.Add(new Item { Data = new byte[20 * 1024 * 1024] });
          db.Items.Add(new Item { Data = new byte[40 * 1024 * 1024] });
          db.Items.Add(new Item { Data = new byte[60 * 1024 * 1024] });
          db.Items.Add(new Item { Data = new byte[80 * 1024 * 1024] });
          db.Items.Add(new Item { Data = new byte[100 * 1024 * 1024] });
          db.Items.Add(new Item { Data = new byte[200 * 1024 * 1024] });
          await db.SaveChangesAsync();
        }
      }
      // Find
      for (int i = 1; i < 8; i++)
      {
        // Find sync - No performance issues
        using (var db = new ItemContext())
        {
          var stopwatch = Stopwatch.StartNew();
          Console.WriteLine("Find sync method doesn't have performance and memory issue");
          Item item = db.Items.Find(i);
          Console.WriteLine($"Record with id '{item.Id}' was fetched in {stopwatch.ElapsedMilliseconds}ms. Press any key to read again...");
        }

        // Find async - performance issues
        using (var db = new ItemContext())
        {
          var stopwatch = Stopwatch.StartNew();
          Console.WriteLine("Reproduce FindAsync performance and memory issue:");
          Item item = await db.Items.FindAsync(i);
          Console.WriteLine($"Record with id '{item.Id}' was fetched in {stopwatch.ElapsedMilliseconds}ms. Press any key to read again...");
        }
      }

      using (var db = new ItemContext())
      {
        db.Database.EnsureDeleted();
      }
    }
  }
}

Performance data
Below image shows the performance details found in the calls between Find() and FindAsync()
image
The id's have the following binary sizes

ID 1 = 2mb
ID 2 = 20mb
ID 3 = 40mb
ID 4 = 60mb
ID 5 = 80mb
ID 6 = 100mb
ID 7 = 200mb

We also found the following memory usage differences
Below images shows the memory 200mb Find()
image

However with FindAsync() we get a lot more usage
Below images shows the memory 200mb FindAsync()
image

But the memory issue is also in EF 6 however not as bad as EF Core
Below images shows the memory 200mb FindAsync()
image

Further technical details

EF Core version: 3.1.4
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET Core 3.0
Operating system: Windows 10 - 1909 (Build 18363.836)
IDE: Visual Studio 2019 - 16.4.1

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions