Last active
February 8, 2024 19:04
-
-
Save davepcallan/2cbcca38fde59c856746d7b8b5dcb78e to your computer and use it in GitHub Desktop.
Entity Framework BulkUpdate v SaveChange v Manual SQL benchmarks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.EntityFrameworkCore; | |
public class MyContext : DbContext | |
{ | |
private int _batchSize; | |
public MyContext(int batchSize = 42) | |
{ | |
_batchSize = batchSize; | |
} | |
public DbSet<Blog> Blogs { get; set; } | |
public DbSet<RssBlog> RssBlogs { get; set; } | |
public DbSet<PrivateBlog> PrivateBlogs { get; set; } | |
public DbSet<PrivateBlogWithMFA> PrivateBlogsWithMFA { get; set; } | |
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) | |
=> optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EF7BulkUpdate;Trusted_Connection=True", opt => opt.MaxBatchSize(_batchSize)); | |
//.EnableSensitiveDataLogging() | |
// .LogTo( | |
// s => Console.WriteLine(s), LogLevel.Information); | |
} | |
public class Blog | |
{ | |
public int BlogId { get; set; } | |
public string Url { get; set; } | |
public bool IsActive { get; set; } | |
public DateTime LastUpdated { get; set; } | |
} | |
public class RssBlog : Blog | |
{ | |
public string RssUrl { get; set; } | |
} | |
public class PrivateBlog : Blog | |
{ | |
public string Password { get; set; } | |
} | |
public class PrivateBlogWithMFA : PrivateBlog | |
{ | |
public bool mfaOn { get; set; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Columns; | |
using BenchmarkDotNet.Configs; | |
using BenchmarkDotNet.Jobs; | |
using BenchmarkDotNet.Reports; | |
using Microsoft.EntityFrameworkCore; | |
using Microsoft.Data.SqlClient; | |
namespace BenchmarkDotNet.Samples | |
{ | |
[Config(typeof(Config))] | |
[SimpleJob(RuntimeMoniker.Net70)] | |
[MemoryDiagnoser] | |
[HideColumns(Column.AllocRatio, Column.RatioSD, Column.Median, Column.Gen0, Column.Gen1)] | |
public class EF7BulkUpdateBenchmark | |
{ | |
private string SQLConnectionString | |
= "Data Source=(localdb)\\mssqllocaldb;Database=EF7BulkUpdate;Integrated Security=sspi;"; | |
[Params(42, 500, 1000)] | |
public int records; | |
[GlobalSetup] | |
public void GlobalSetup() | |
{ | |
using var context = new MyContext(); | |
context.Database.EnsureDeleted(); | |
context.Database.EnsureCreated(); | |
var random = new Random(); | |
var date = DateTime.UtcNow; | |
for (int i = 0; i < records; i++) | |
{ | |
context.Add(new | |
Blog | |
{ | |
Url = "https://blogurl/ID/" + random.Next(1, 10000).ToString(), | |
LastUpdated = date | |
}); | |
} | |
context.SaveChanges(); | |
} | |
[Benchmark] | |
public void ADONET_PlainSQL_BulkUpdate() | |
{ | |
using (SqlConnection connection = new SqlConnection(SQLConnectionString)) | |
{ | |
connection.Open(); | |
using (SqlCommand command = | |
new SqlCommand("UPDATE [Blogs] SET [LastUpdated] = @date; --ADONETUpdate", connection)) | |
{ | |
command.Parameters.AddWithValue("@date", DateTime.UtcNow); | |
command.ExecuteNonQuery(); | |
} | |
} | |
} | |
[Benchmark] | |
public void EF_PlainSQL_BulkUpdate() | |
{ | |
using var context = new MyContext(); | |
context.Database | |
.ExecuteSql($"UPDATE [Blogs] SET [LastUpdated] = {DateTime.UtcNow}; --PlainSQLUpdate"); | |
} | |
[Benchmark(Baseline = true)] | |
public void EF_ExecuteUpdate_BulkUpdate() | |
{ | |
using var context = new MyContext(); | |
context.Blogs.ExecuteUpdate( | |
s => s.SetProperty( | |
blog => blog.LastUpdated, DateTime.UtcNow)); | |
} | |
[Benchmark] | |
public void EF_SaveChanges_NoBulkUpdate() | |
{ | |
using var context = new MyContext(); | |
var date = DateTime.UtcNow; | |
var blogs = context.Blogs.ToList(); | |
foreach (var blog in blogs) | |
{ | |
blog.LastUpdated = date; | |
} | |
context.SaveChanges(); | |
} | |
private class Config : ManualConfig | |
{ | |
public Config() | |
{ | |
SummaryStyle = | |
SummaryStyle.Default.WithRatioStyle(RatioStyle.Percentage); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using BenchmarkDotNet.Running; | |
namespace EF7Benchmarks | |
{ | |
internal class Program | |
{ | |
static void Main(string[] args) | |
{ | |
BenchmarkSwitcher. | |
FromAssembly(typeof(Program).Assembly).Run(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment