【发布时间】:2020-12-17 13:38:45
【问题描述】:
问题: 我注意到同时开始的实体框架调用的处理时间越来越长。该程序是 .NET Core 2.2,带有 EF 2.2
以下是演示该行为的日志示例:
在第 30 次查询时持续长达 10 秒。
调查:
为了重现和测试这一点,我创建了一个简单的可执行文件,它将并行调用方法 Test() 20 次,Test() 从 ServiceProvider 获取作用域上下文,并对数据库进行查询。我已经执行了几次,并显示了每个设置的 3 个结果的屏幕截图。注意:Query() 方法在 20 次测试之前运行一次,允许 EF 生成查询缓存
private async Task Test()
{
List<Task> tasks = new List<Task>();
// Populate the queue.
for (int i = 0; i < 10000; i++)
{
cq.Enqueue(i);
}
Query();
Thread.Sleep(1000);
Query();
Thread.Sleep(1000);
for (int i = 0; i < 20; i++)
{
tasks.Add(Task.Run(() => Query()));
}
await Task.WhenAll(tasks);
}
private async Task Query()
{
cq.TryDequeue(out int id);
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: started");
using (var serviceScope = _serviceProvider.CreateScope())
{
var watch = new Stopwatch();
var ctx = serviceScope.ServiceProvider.GetService<Core.Models.MyContext>();
watch.Start();
var quoteLineJob = await ctx.QuoteLineJobs
.FirstOrDefaultAsync(o => o.Id == id);
watch.Stop();
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: Quote line job loaded in {watch.ElapsedMilliseconds}ms");
}
}
我无法理解结果,希望有人能提出一个假设:
加载时间越来越长
- 从开发人员机器到生产数据库
但是,访问相同的数据库,结果要慢得多。
- 随机服务器到生产数据库
结果与开发人员的机器非常相似,但是,它有 50% 的可能性是随机行为(参见第三个结果)而不是增量
我想补充一点,查看 SQL Server Profiler,对于所有设置,所有同时查询的读取查询需要 0 毫秒。
好像这并不令人困惑,当我在 localhost 上尝试相同的测试时:
- 开发者的机器到开发者的数据库(生产中的数据库副本,相同的数据)
这里的结果是随机的,不递增
- 随机服务器到随机服务器数据库
同样,加载时间是随机的,不会增加
有没有人看到一些模式,以及为什么 Entity Framework 会有这样的行为?
【问题讨论】:
-
请提供代码块中的代码,而不是图片,这样会更方便其他人提供帮助
-
可能您的 DbContext 存在时间过长,并且一直跟踪通过它的所有实体。使用代码而不是图像提供minimal reproducible example。
-
让我猜可能不是你的情况。在运行查询之前,它应该被翻译成 SQL、生成的映射器等。它在 EF 中可能是一个缓慢的过程,所以 EF 正在缓存已翻译的查询。如果很多线程开始执行相同的查询 - 他们错过了缓存。这意味着许多线程开始翻译相同的 LINQ 查询。一旦一个线程完成翻译 - 查询存储在缓存中,尚未开始运行的新线程重用已翻译的 LINQ 查询 - 并更快地开始工作。
-
@SvyatoslavDanyliv,这是一个很好的观点,我实际上忘了说我在 20 个测试开始之前运行了一次查询,这是一个需要 3-7 秒的慢速查询,所以所有的它们从缓存中运行。我已经编辑了我的帖子,请查看代码
-
那么,如果您使用
new Your context(),它是否可以在没有 DI 的情况下工作? DI 长什么样子?
标签: c# entity-framework .net-core entity-framework-core