实体框架在每次编译后的第一次加载非常慢

本文关键字:第一次 加载 非常 编译 框架 实体 | 更新日期: 2023-09-27 17:50:37

正如标题所示,我对使用实体框架的SQL Server数据库的第一个查询有问题。我试着寻找一个答案,但似乎没有人真正有一个解决方案。

测试是在Visual Studio 2012中使用实体框架6完成的,我还使用T4视图模板来预编译视图。数据库使用的是SQL Server 2008。我们有大约400个poco(400个映射文件),在数据库表中只有100行数据。

下面是我的测试代码和结果。

static void Main(string[] args){
    Stopwatch st=new Stopwatch();
    st.Start();
    new TestDbContext().Set<Table1>.FirstOrDefault();
    st.stop();
    Console.WriteLine("First Time "+st.ElapsedMilliseconds+ " milliseconds");
    st.Reset();
    st.Start();
    new TestDbContext().Set<Table1>.FirstOrDefault();
    st.stop();
    Console.WriteLine("Second Time "+st.ElapsedMilliseconds+ " milliseconds");
}
测试结果

First Time 15480 milliseconds
Second Time 10 milliseconds

实体框架在每次编译后的第一次加载非常慢

在第一个查询中EF编译模型。对于这么大的模型来说,这可能需要很长时间。

这里有3个建议:http://www.fusonic.net/en/blog/2014/07/09/three-steps-for-fast-entityframework-6.1-first-query-performance/

一个总结:

  1. 使用缓存的数据库模型存储
  2. 生成预编译视图
  3. 使用n-gen生成预编译版本的entityframework,以避免jit

我还会确保在做基准测试时以发布模式编译应用程序。

另一个解决方案是拆分DBContext。400个实体太多了,使用更小的块应该会更好。我没有尝试过,但我认为有可能一个接一个地构建模型,这意味着没有单次加载需要15秒。参见Julie Lerman的文章https://msdn.microsoft.com/en-us/magazine/jj883952.aspx

使用EF Core,您可以在调用services.AddDbContext之后欺骗并加载模型(您也可以对EF6做类似的事情,但我还没有测试过)。

services.AddDbContext<MyDbContext>(options => ...);
var options = services.BuildServiceProvider()
                      .GetRequiredService<DbContextOptions<MyDbContext>>();
Task.Run(() =>
{
    using(var dbContext = new MyDbContext(options))
    {
        var model = dbContext.Model; //force the model creation
    }
});

这将在另一个线程中创建dbcontext的模型,同时完成应用程序的其余初始化(可能还有其他预热)和请求的开始。这样,它会准备得更快。当你需要它的时候,EFCore将等待模型被创建,如果它还没有完成的话。Model在所有DbContext实例之间共享,因此可以启动并忘记这个虚拟DbContext。

你可以尝试这样做:(它为我工作)

protected void Application_Start()
{
    Start(() =>
    {
        using (EF.DMEntities context = new EF.DMEntities())
        {
            context.DMUsers.FirstOrDefault();
        }
    });
}
private void Start(Action a)
{
    a.BeginInvoke(null, null);
} 

实体框架-第一次查询慢

this work for me:

using (MyEntities db = new MyEntities())                
{
   db.Configuration.AutoDetectChangesEnabled = false; // <----- trick
   db.Configuration.LazyLoadingEnabled = false; // <----- trick
   DateTime Created = DateTime.Now;
   var obj = from tbl in db.MyTable
      where DateTime.Compare(tbl.Created, Created) == 0
      select tbl;
   dataGrid1.ItemsSource = obj.ToList();
   dataGrid.Items.Refresh();
}

如果你有很多没有在c#上使用的表,排除它们。

添加一个局部类,添加以下代码并在OnModelCreating

上引用这个函数
void ExcludedTables(DbModelBuilder modelBuilder)
{
    modelBuilder.Ignore<Table1>();
    modelBuilder.Ignore<Table>();
   // And so on
}

对我来说,只是在第一个查询中使用AsParallel()解决了这个问题。这在多个处理器核心上运行查询(显然)。我所有的后续查询都是不变的,只有第一个查询导致了延迟。

我还尝试了预生成的映射视图https://learn.microsoft.com/en-us/ef/ef6/fundamentals/performance/pre-generated-views,但这并没有提高启动时间。

我认为这不是一个很好的解决方案。Ado.net看起来性能更好。然而,这是我的观点。

或者看看他们。

https://msdn.microsoft.com/tr-tr/data/dn582034

https://msdn.microsoft.com/en-us/library/cc853327 (v = vs.100) . aspx