【问题标题】:Entity framework very slow to load for first time after every compilation每次编译后第一次加载实体框架非常慢
【发布时间】:2015-08-06 01:53:02
【问题描述】:

正如标题所示,我在使用实体框架对 SQL Server 数据库进行第一次查询时遇到问题。我曾尝试寻找答案,但似乎没有人能真正解决这个问题。

测试是在 Visual Studio 2012 中使用 Entity Framework 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

【问题讨论】:

    标签: c# sql-server entity-framework


    【解决方案1】:

    在第一个查询中,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 生成实体框架的预编译版本以避免抖动

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

    另一种解决方案是查看拆分 DBContext。 400 个实体很多,使用较小的块应该会更好。我还没有尝试过,但我认为可以一个一个地构建模型,这意味着没有单个负载需要 15 秒。请参阅 Julie Lerman https://msdn.microsoft.com/en-us/magazine/jj883952.aspx 的这篇文章

    【讨论】:

    • 我必须使用 Davidroth' EF.dll 和 EntityFramework.SqlServer.dll 吗?我下载了源代码并添加了对我的解决方案的引用,但在运行时,它会引发异常。异常信息:无法加载文件或程序集“Entityframework, version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089” ....
    • 很高兴为您提供帮助。它变得快了多少?
    • 从15秒到5秒,让我痛了很久,
    • @MikaelEliasson 文章中介绍的工具(“nuget package: Interactive Pregenerated Views for Entity Framework 6.”和“github上的DbModelStore分支 ") 在 2014 年之后没有更新。我们现在可以使用哪些替代工具或方法?
    • 另一个建议是在第一次加载应用程序时调用模型
    【解决方案2】:

    使用 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。

    【讨论】:

    • services.BuildServiceProvider() 根本不应该被称为Dependency injection in ASP.NET Core。您应该只在 ConfigureServices 中调用 services.AddDbContext&lt;MyDbContext&gt;(options =&gt; ...); 并将其注入到 Configure public void Configure(..., MyDbContext dbContext) 中,然后只注入 Task.Run(() =&gt; { _ = dbContext.Model; });
    【解决方案3】:

    你可以试试这样的:(对我有用)

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

    Entity Framework - First query slow

    【讨论】:

    • 我发现如果使用另一个线程来初始化 EF,并在短时间内在主线程中使用 EF,它可能会调用 Multi Thread access EF Exception, not thread safe 异常,ex msg 的意思就是这个意思,所以我认为如果使用another thread initreally use EF in main thread 两个动作是关闭的,我可能不想使用另一个线程来初始化,以避免异常。
    【解决方案4】:

    这对我有用:

    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();
    }
    

    【讨论】:

      【解决方案5】:

      如果您有许多未在 c# 上使用的表,请将它们排除在外。

      添加部分类,添加如下代码并在 OnModelCreating 上引用该函数

      void ExcludedTables(DbModelBuilder modelBuilder)
      {
          modelBuilder.Ignore<Table1>();
          modelBuilder.Ignore<Table>();
         // And so on
      }
      

      【讨论】:

        【解决方案6】:

        对我来说,只需在第一个查询中使用 AsParallel() 即可解决问题。这会在多个处理器内核上运行查询(显然)。我随后的所有查询都没有改变,只是第一个导致延迟。

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

        【讨论】:

          【解决方案7】:

          我认为这不是一个很好的解决方案。 Ado.net 看起来性能要好得多。不过,这是我的看法。

          换个方式看看它们。

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-04-22
            • 2020-12-03
            • 1970-01-01
            • 2014-09-20
            • 1970-01-01
            • 2023-02-26
            • 1970-01-01
            • 2017-09-05
            相关资源
            最近更新 更多