.net 实体框架-第一个查询速度慢

.net 实体框架-第一个查询速度慢,.net,performance,entity-framework,.net,Performance,Entity Framework,正如标题所示,我在使用实体框架对SQLServer数据库进行第一次查询时遇到了问题 我曾尝试在不同的网站上寻找答案,但似乎没有人能真正解决这个问题 我正在从数据库加载相当多的行,包括两个0-many关系 测试是在VisualStudio2010中使用EntityFramework4.0模型和POCO生成器完成的(普通实体和POCO对象之间的计时没有太大差异)。我还使用T4视图模板预编译视图 数据库位于SQL Server 2008上 我真正想知道的是为什么第一个查询比任何第二个查询都慢得多 我还

正如标题所示,我在使用实体框架对SQLServer数据库进行第一次查询时遇到了问题

我曾尝试在不同的网站上寻找答案,但似乎没有人能真正解决这个问题

我正在从数据库加载相当多的行,包括两个0-many关系

测试是在VisualStudio2010中使用EntityFramework4.0模型和POCO生成器完成的(普通实体和POCO对象之间的计时没有太大差异)。我还使用T4视图模板预编译视图

数据库位于SQL Server 2008上

我真正想知道的是为什么第一个查询比任何第二个查询都慢得多

我还想知道是否可以做一些事情来提高第一个查询的速度,使其在可接受的范围内

这是一个大查询,我们可能会得到其他更大的查询,可以理解,它们可能有点慢,但30秒对于用户来说太慢了,无法等待,特别是当数据集可以更快地获得相同的数据时

我已经做了一些计时测试,试图找出问题所在。我有点惊讶地看到,第一次查询速度慢的似乎是SQL Server

时间安排如下:

.NET测试应用程序:

  • 第一次查询:29,6秒
  • 第二次查询:3.2秒
SQL分析器:

  • 第一个查询:27秒
  • 第二次查询:3.2秒
SQL Server查询窗口

  • 第一个查询:8秒
  • 第二次查询:4秒
应用程序中的计时使用
秒表
类进行测量。仅测量查询,并使用
.ToList()
执行查询

SQL Server Profiler中的计时与应用程序中执行的查询相同,这表明应用程序只需2,6秒即可将数据填充到对象中

最后27秒用于在SQL Server上执行查询

查看二次查询,应用程序和SQL server的计时都相同,但这次执行查询的速度要快得多

我可以理解为什么应用程序不使用任何时间,因为没有需要转换为对象的新行,但为什么查询速度要快得多,因为执行计划,我本来希望几秒钟,但不是24秒钟

出于测试目的,我复制了实体框架生成的SQL,并使用单独的连接打开了一个新的查询窗口,并在其中执行了查询

如您所见,第一次查询需要8秒,第二次查询需要4秒

我希望有人能提出一些建议

注:我为文字墙道歉:)

2010年10月19日编辑:
我昨天做了一个测试,它似乎支持按顺序返回行。这意味着当从数据库返回一行时,它会立即被物化(如果上下文中不存在),然后返回下一行,依此类推

这就是为什么查询在数据库服务器上花费大量时间的原因,因为具体化时间包含在SQL server探查器计时中

我认为这不是SQL Server从硬盘读取数据的情况。 每次EF中有“第一次查询”时,都会发生慢速查询

  • 使用EF运行第一个查询,SQL语句比任何第二个查询都慢
  • 处置上下文/存储库
  • 创建一个新的上下文
  • 运行与前面相同的查询(同样,第一个查询速度较慢,SQL语句也较慢)
  • 这几乎就像EF在第一次查询时发送一些选项,这会使服务器运行缓慢

    至于查询编译,正如我所记得的,查询是在第一次使用时编译的,这意味着第一个查询将需要更长的时间来执行

    二次查询会更快,但二次查询的速度不是问题所在

    我还做了一个测试,其中我创建了一个编译后的查询作为一个静态查询,以便为创建的所有上下文进行编译

    然后我创建了一个上下文,运行了查询,销毁了上下文,创建了一个新的上下文,并再次运行了相同的查询

    差别并没有那么大,只有几秒钟,而我第一次运行查询时,仍然需要花费与未预编译时一样长的时间

    至于视图生成,我们已经使用T4模板实现了这一点

    答案真的是EF只有在只返回相对较少数据量的最简单查询时才起作用吗?

    很多事情都会使SQL Server查询在第一次运行时变慢。然而,其中大多数并不需要几秒钟

    …除了硬盘随机访问。第一次运行查询时,SQL Server可能必须从硬盘存储中读取数据库页。下次运行查询时,这些页面可能会在内存中

    关于实体框架,第一次运行查询时必须将其编译为SQL。您可以使用
    CompiledQuery
    类型预编译实体框架查询,以便在最终用户等待之前提前完成这项工作


    在非常大的模型上,视图生成也需要一些时间。您可以将其移动到编译时。请参阅以了解更多此类提示。

    我们在EF 5.0中也遇到了同样的问题,到今天为止,一个肤浅的谷歌搜索还没有显示出足够的速度

    根据这个链接,“加载元数据”的时间开销适中,但每个AppDomain只需要加载一次。我没有发现像预编译这样的加载元数据的技巧

    我们实现的解决方法是在应用程序启动时,在一个单独的线程中对上下文执行一个小查询。这负载
     protected void Application_Start()
        {
    
            Start(() =>
            {
                using (EF.DMEntities context = new EF.DMEntities())
                {
                    context.DMUsers.FirstOrDefault();
                }
            });
        }
        private void Start(Action a)
        {
            a.BeginInvoke(null, null);
        }