1


Entity Framework 7 insert performance improvement versus EF 6 benchmark




Date Added (UTC):

14 Apr 2024 @ 23:09

Date Updated (UTC):

14 Apr 2024 @ 23:09


.NET Version(s):

.NET 8

Tag(s):

#DBOperations #EntityFramework


Added By:
Profile Image

Blog   
Ireland    
.NET Developer and tech lead from Ireland!

Benchmark Results:





Benchmark Code:



using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using Microsoft.EntityFrameworkCore;
using BenchmarkDotNet.Reports;
using System.Threading.Tasks;

[Config(typeof(Config))]
[MemoryDiagnoser]
[HideColumns(Column.AllocRatio, Column.RatioSD, Column.Median, Column.Gen0, Column.Gen1, Column.NuGetReferences)]
public class EF7Perf
{
    private class Config : ManualConfig
    {
        public Config()
        {
            SummaryStyle =
                SummaryStyle.Default
                .WithRatioStyle(RatioStyle.Percentage)
                .WithTimeUnit(Perfolizer.Horology.TimeUnit.Millisecond);

            var baseJob = Job.Default;

            AddJob(baseJob.WithNuGet("Microsoft.EntityFrameworkCore.SqlServer", "8.0.4")
                .WithId("EF 8.0.4"));
            AddJob(baseJob.WithNuGet("Microsoft.EntityFrameworkCore.SqlServer", "7.0.18")
                .WithId("EF 7.0.18"));
            AddJob(baseJob.WithNuGet("Microsoft.EntityFrameworkCore.SqlServer", "6.0.29")
                .WithId("EF 6.0.29")
                .WithBaseline(true));
        }
    }

    [Params(100)]
    public int NumBlogs { get; set; }

    [GlobalSetup]
    public void GlobalSetup()
    {
        using var context = new BloggingContext();
        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();
    }

    [Benchmark]
    public async Task InsertRows()
    {
        var db = new BloggingContext();

        for (var i = 0; i < NumBlogs; i++)
        {
            var blog = new Blog { Name = "Foo" + i, Url = "Bar" + i };
            db.Blogs.Add(blog);
        }

        await db.SaveChangesAsync();
    }

    public class BloggingContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            => optionsBuilder.UseSqlServer(
                @"Server=localhost;Database=efsamples;Trusted_Connection=True;TrustServerCertificate=true");
    }

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

// .NET 8 Lowered C# Code unavailable due to errors:
error CS0234: The type or namespace name 'EntityFrameworkCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
error CS0246: The type or namespace name 'DbContext' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbSet<>' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbContextOptionsBuilder' could not be found (are you missing a using directive or an assembly reference?)
error CS1674: 'EF7Perf.BloggingContext': type used in a using statement must be implicitly convertible to 'System.IDisposable'.
error CS1061: 'EF7Perf.BloggingContext' does not contain a definition for 'Database' and no accessible extension method 'Database' accepting a first argument of type 'EF7Perf.BloggingContext' could be found (are you missing a using directive or an assembly reference?)
error CS1061: 'EF7Perf.BloggingContext' does not contain a definition for 'SaveChangesAsync' and no accessible extension method 'SaveChangesAsync' accepting a first argument of type 'EF7Perf.BloggingContext' could be found (are you missing a using directive or an assembly reference?)

// .NET 8 IL Code unavailable due to errors:
error CS0234: The type or namespace name 'EntityFrameworkCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
error CS0246: The type or namespace name 'DbContext' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbSet<>' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbContextOptionsBuilder' could not be found (are you missing a using directive or an assembly reference?)
error CS1674: 'EF7Perf.BloggingContext': type used in a using statement must be implicitly convertible to 'System.IDisposable'.
error CS1061: 'EF7Perf.BloggingContext' does not contain a definition for 'Database' and no accessible extension method 'Database' accepting a first argument of type 'EF7Perf.BloggingContext' could be found (are you missing a using directive or an assembly reference?)
error CS1061: 'EF7Perf.BloggingContext' does not contain a definition for 'SaveChangesAsync' and no accessible extension method 'SaveChangesAsync' accepting a first argument of type 'EF7Perf.BloggingContext' could be found (are you missing a using directive or an assembly reference?)

// .NET 8 Jit Asm Code unavailable due to errors:
error CS0234: The type or namespace name 'EntityFrameworkCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
error CS0246: The type or namespace name 'DbContext' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbSet<>' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name 'DbContextOptionsBuilder' could not be found (are you missing a using directive or an assembly reference?)
error CS1674: 'EF7Perf.BloggingContext': type used in a using statement must be implicitly convertible to 'System.IDisposable'.
error CS1061: 'EF7Perf.BloggingContext' does not contain a definition for 'Database' and no accessible extension method 'Database' accepting a first argument of type 'EF7Perf.BloggingContext' could be found (are you missing a using directive or an assembly reference?)
error CS1061: 'EF7Perf.BloggingContext' does not contain a definition for 'SaveChangesAsync' and no accessible extension method 'SaveChangesAsync' accepting a first argument of type 'EF7Perf.BloggingContext' could be found (are you missing a using directive or an assembly reference?)


Benchmark Description:


EF 7 brought a lot of performance improvements around inserts due to roundtrip reductions and optimization of the MERGE statement it uses for inserts.

The provided benchmark code is designed to measure and compare the performance of different versions of Entity Framework Core (EF Core) when performing database operations, specifically inserting rows into a database. The benchmark is set up using BenchmarkDotNet, a powerful .NET library for benchmarking, and targets the Microsoft.EntityFrameworkCore.SqlServer package with three different versions: 8.0.4, 7.0.18, and 6.0.29. The setup and each method's rationale are explained below: ### General Setup - **.NET Version**: The .NET version isn't explicitly mentioned, but given the versions of EF Core being benchmarked, it's likely targeting .NET Core 3.1 or .NET 5/6 due to compatibility. - **BenchmarkDotNet Configuration**: - **MemoryDiagnoser**: Enabled to collect and report memory allocation statistics. - **HideColumns**: Certain columns like allocation ratio, standard deviation of the ratio, median, Gen0, Gen1, and NuGet references are hidden to focus the report on more relevant metrics. - **Jobs**: Three jobs are configured, each targeting a different version of `Microsoft.EntityFrameworkCore.SqlServer` (8.0.4, 7.0.18, and 6.0.29), with the 6.0.29 version marked as the baseline. This setup allows for performance comparison across versions. - **SummaryStyle**: Configured to display ratios in percentage and time measurements in milliseconds for easier interpretation. ### Benchmark Method: `InsertRows` - **Purpose**: This method aims to benchmark the performance of inserting a specified number of rows into a database using EF Core. It's designed to test how efficiently each version of EF Core can handle insert operations, which is a common task in many applications. - **Performance Aspect**: The focus is on measuring the time it takes to insert a fixed number of rows (`NumBlogs`) into a database and the memory allocations involved in this process. This provides insights into the efficiency and scalability of the different EF Core versions for write operations. - **What It Measures**: The method measures the asynchronous execution time of inserting `NumBlogs` rows into a database and the memory allocated during this operation. It uses a loop to create and add new `Blog` entities to the context and then calls `SaveChangesAsync` to persist changes to the database. - **Why It's Important**: Insert operations are fundamental to database interaction, and their performance directly impacts the responsiveness and scalability of applications. By benchmarking this operation across different versions of EF Core, developers can make informed decisions about which version to use based on performance considerations. - **Expected Results/Insights**: From running this benchmark, one should expect to see how the performance (in terms of execution time and memory allocation) of insert operations varies across the different versions of EF Core. Ideally, newer versions would show improvements in performance and efficiency due to optimizations in the framework. However, actual results can vary based on many factors, including changes in the framework's internals, the specific workload, and the database setup. ### Conclusion This benchmark setup and the specific `InsertRows` method provide valuable insights into the performance characteristics of different versions of EF Core when performing insert operations. Such benchmarks are crucial for performance tuning and making informed decisions about framework versions in the context of application requirements and constraints.


Benchmark Comments: