Performance issue when querying varbinary(MAX), varchar(MAX), nvarchar(MAX) or XML with Async
See original GitHub issueDescription
I would like to resurrect the following EF6 issue: https://github.com/aspnet/EntityFramework6/issues/88 because it’s still present in EF Core 2.2 and 3.0 also.
There’s a huge performance issue when querying a table containing varbinary(MAX) columns with .ToListAsync(). The problem is EF, despite the presence of varbinary(max) column, uses CommandBehavior.Default with ExecuteReaderAsync(). (instead of CommandBehavior.SequentialAccess)
Related SO question and answer: https://stackoverflow.com/questions/28543293/entity-framework-async-operation-takes-ten-times-as-long-to-complete
This is a huge issue, we cannot use ToList
as a workaround because this requires impossible checks at development time.
Steps to reproduce
I have created a small repro codebase and benchmarks.
public class AppDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=EFCore-repro-ToListAsync;Trusted_Connection=True;");
}
public DbSet<TestEntity> Blobs { get; set; }
}
public class TestEntity
{
public int Id { get; set; }
public string LargeTextBlob { get; set; }
}
public class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<Benchmarks>();
Console.ReadKey();
}
}
public class Benchmarks
{
private int id;
public Benchmarks()
{
using (var context = new AppDbContext())
{
var array = new char[5 * 1024 * 1024];
var random = new Random();
for (int i = 0; i < array.Length; i++)
{
array[i] = (char)random.Next(32, 126);
}
var entity = new TestEntity { LargeTextBlob = new string(array) };
context.Blobs.Add(entity);
context.SaveChanges();
id = entity.Id;
}
}
[Benchmark]
public void GetWithToList()
{
using (var context = new AppDbContext())
{
var entity = context.Blobs.Where(b => b.Id == id).ToList();
}
}
[Benchmark]
public async Task GetWithToListAsync()
{
using (var context = new AppDbContext())
{
var entity = await context.Blobs.Where(b => b.Id == id).ToListAsync();
}
}
}
Benckmarks
Method | Mean | Error | StdDev |
---|---|---|---|
GetWithToList | 45.63 ms | 0.4871 ms | 0.4318 ms |
GetWithToListAsync | 15,088.37 ms | 178.2588 ms | 158.0218 ms |
Further technical details
EF Core version: 2.2, 3.0 Database provider: (e.g. Microsoft.EntityFrameworkCore.SqlServer) Target framework: (e.g. .NET Core 3.0, .NET Core 2.2) Operating system: Windows 10. IDE: (e.g. Visual Studio 2019 16.3)
Issue Analytics
- State:
- Created 4 years ago
- Reactions:12
- Comments:11 (6 by maintainers)
@SokoFromNZ and others, this has nothing to do with EF Core; this issue tracking the problem is https://github.com/dotnet/SqlClient/issues/593.
@rogerfar the problem really is in the SqlClient provider - I’d advise upvoting the issue there to help them prioritize it more.