Entity Framework Core 3.1 Bug vs 2.2, Speed and Memory During Streaming

Full source code available here.

A while ago I wrote a blog post about the advantages of streaming results from Entity Framework Core as opposed to materializing them inside a controller and the returning the results. I saw very significant improvements in memory consumption when streaming as shown in the chart below.

For this post I updated the code to use Entity Framework Core 3.1.8 on .NET Core 3.1 and was very surprised to see that streaming data did not work as before. Memory usage was high and the speed of the response was much poorer than I expected.

I tried Entity Framework Core 2.2.6 on .NET Core 3.1, and it behaved as I expected, fast and low memory.

Below is how I carried out my comparison.

The Setup

A simple Web API application using .NET Core 3.1.

A local db seeded with 10,000 rows of data using AutoFixture.

An API controller with a single action method that returns data from the database. Tracking of Entity Framework entities is turned off.

 1[Route("api/[controller]")]
 2[ApiController]
 3public class ProductsController : ControllerBase
 4{
 5    private readonly SalesContext _salesContext;
 6
 7    public ProductsController(SalesContext salesContext)
 8    {
 9        _salesContext = salesContext;
10    }
11
12    [HttpGet("streaming/{count}")]
13    public ActionResult GetStreamingFromService(int count)
14    {
15        IQueryable<Product> products = _salesContext.Products.OrderBy(o => o.ProductId).Take(count).AsNoTracking();
16        return Ok(products);
17    }
18}

It’s a very simple application.

The Test

I “warm up” the application by making a few requests.

Then I use Fiddler to hit the products endpoint 20 times, each request returns 8,000 products.

I do the same for both Entity Framework Core 3.1.8 and Entity Framework Core 2.2.6.

The Results

Framework Core 2.2.6 out performs Framework Core 3.1.8 in both speed of response and memory consumption.

Here is the comparison of how quickly they both load the full set of results.

Time to First Byte (TTFB) -

  • EF 2.2.6 returns data before we even reach 10ms in all cases and before 2ms in most cases.
  • EF 3.1.8 is never faster than 80ms and six requests take more than 100ms.

Overall Elapsed -

  • EF 2.2.6 returns most requests in the 26ms to 39ms range, with only two taking more than 40ms.
  • EF 3.1.8 returns four requests in less than 100ms. The rest are in the 100ms to 115ms range.

The speed difference between EF Core 2.2.6 and EF Core 3.1.8 is significant, to say the least.

Memory Usage -

Here is the graph of memory usage during the test.

  • EF Core 2.2.6 maintains low memory usage.
  • EF Core 3.1.8 consumes significantly more memory to do the same job.
Remember, they are both using the same application code, it's only the versions of Entity Framework that differ.

I also performed tests with other versions of Entity Framework Core 3.1., and Entity Framework 2. and same very similar results. It seems something in the 3.1 stack is done very differently than the 2.* stack.

As always, you can try it for yourself with the attached zip.

Full source code available here.

comments powered by Disqus

Related