我最近确定,在 .NET Core 中使用依赖注入的 DbContext 并使用异步等待调用(而不是每次要访问数据库时都创建新的 DbContext)不会显著提高性能。
但现在我需要知道为什么。
我在 .NET Core 1.1 API 服务(控制器正在调用)中使用 System.Diagnostics.Stopwatch 进行了更精细的测试,其中我仅在访问数据库时运行秒表。结果令人惊讶。
使用标准依赖关系注入上下文和异步/等待调用时:
var task1 = _InjectedDbContext.Table1.FirstOrDefaultAsync(p => p.Id == SomeId);
var task2 = _InjectedDbContext.Table2.Where(u => u.AnotherId == SomeOtherId).ToListAsync();
(var result1, var result2) = await (task1, task2).WhenAll();
每个 DbContext 查询花费的时间明显少于 100 毫秒。
但是,使用此方法时:
using (var context = new DbContext(_InjectedContextOptions.Options))
{
var task1 = context.Table1.FirstOrDefaultAsync(p => p.Id == SomeId);
var task2 = context.Table2.Where(u => u.AnotherId == SomeOtherId).ToListAsync();
(var result1, var result2) = await (task1, task2).WhenAll();
}
每个 DbContext 查询需要 100-230 毫秒的时间。
仅供参考,这是我在启动.cs配置服务中用于 DI 设置的代码:
var connection = Configuration.GetConnectionString("mydb");
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connection));
这是我的代码,每当我创建新的 DbContext 时,都会将 DbContextOptions 作为单例提供:
var dbContextOptions = new DbContextOptionsBuilder<MyDbContext>();
dbContextOptions.UseSqlServer(Configuration.GetConnectionString("MyDb"));
services.AddSingleton(dbContextOptions);
我还确定滞后不是由简单地在 using 语句中创建 DbContext 引起的(这是一个非常快的操作)。这是怎么回事?是每次都尝试重新连接到数据库还是其他什么?
您正在使用 AddDbContext 方法,用于您在第一个方案中使用的 DbContext,该方法将 DbContext 作为 Scoped 添加到服务中(如果我没记错的话)。由于优化,DbContext 可能在添加服务后立即初始化(此处不确定)。对于第二种情况,您将创建一个新的 DbContext。除了创建 DbContext 之外,还有一些其他的事情需要完成。
摘自这篇文章,这里有一些提示来"热身"你的环境:
- 使用缓存的数据库模型存储
- 生成预编译视图
- 使用 n 代生成实体框架的预编译版本以避免抖动
上面的提示表明,使用 DbContext 不仅仅是"仅仅"更新一个并开始查询。