我是第一次使用 Entity Framework Core,当我试图理解为什么每次启动项目时执行第一个查询时速度太慢(大约 2-3 秒)时,我感到非常困惑。
为了给您提供额外信息,我可以说我正在开发一个 .NET 6 项目,.NET 框架的版本是 7.0.18,因为它是与我的 .NET 版本兼容的最后一个版本。
这是我调用来执行查询的方法:
public async Task<string> GetField()
{
using ContextClass context = new ContextClass();
var variable = await context.Table
.FirstOrDefaultAsync(v => v.Id == 429719);
return variable?.Field ?? "a"; //If nothing is found, it will retrieve an empty string
}
我可以看到的是,如果我调用相同的方法(或从另一个方法调用另一个方法
DataContext
),它将不会再花费这些秒,并且结果将立即返回。
我目前找到的解决方案是创建一个“初始化器”类,它执行以下操作:
public class Initializer
{
public Initializer() { }
public async void DbInitializer()
{
using (var context = new CodisContext())
{
await context.Database.EnsureCreatedAsync();
}
}
}
调用
DbInitializer
函数使第一个查询按预期运行。
您有任何提示或建议来避免使用此方法吗?
针对 DbContext 的第一个查询将需要等待 EF 初始化其模型。 DbContext 越大、越复杂,花费的时间就越长。对于 Web 应用程序,只要应用程序池回收,就会发生这种情况,其中可能包括将站点设置为在空闲时保留资源的情况。 (空闲超时)
类似初始化程序的东西,或者只是执行一个简单的查询,例如:
using var context = new CodisContext();
context.Table.Any();
...当您的应用程序池启动时足以触发首次运行预热成本。 (即就在
app.Run()
之前)
或者,如果您有一个大型、复杂的模式可供使用,您可以考虑将其拆分为较小的有界 DbContext,其中每个 DbContext 负责应用程序中的一个关键区域。如果较小的上下文不需要完整的信息,则可以使用表格的简化表示,这样可以更简单、更快速地使用。
对于从实体返回单个字段或字段子集,利用投影来构建高效的查询。您的示例可能只是一个简单的演示查询,但如果您的代码只想从一条或多条记录中检索一些信息:
var variable = await context.Table
.Where(v => v.Id == id)
.Select(v => v.Field)
.FirstOrDefaultAsync();
return variable ?? DefaultValue;
您的示例与上面的示例之间的区别在于,在您的情况下,当您只关心一列时,您将执行查询以从数据库中检索整个记录。该实体也将不必要地添加到 EF 的跟踪缓存中。仅应在您想要更新实体的地方执行此操作,以便您可以更改该实体并调用
SaveChanges()
让 EF 构建适当的 UPDATE
语句。对于简单的读取操作,上面的查询将仅构建一个 SQL 语句来检索单个所需的列(如果找到)。在具有许多潜在大列的较大表上,这可以在性能和资源使用方面产生非常明显的差异。