【问题标题】:Entity Framework takes about 30 seconds on first query实体框架在第一次查询时大约需要 30 秒
【发布时间】:2016-09-21 12:21:25
【问题描述】:

我在 SQL Server 数据库上使用 Entity Framework 6 来查询现有数据库(首先是数据库,所以我的项目中有一个 EDMX)。

我注意到,第一次请求实体时,执行查询可能需要 30 秒。随后对同一对象的查询将在几毫秒内完成。实际执行的 SQL 非常快,所以查询并不慢。

我发现 Entity Framework 在背景上生成视图,这很可能是罪魁祸首。然而,我还没有找到一个很好的解决方案。有一个可以处理视图生成 (EFInteractiveViews) 的 NuGet 包,但它自 2014 年以来一直没有更新,我似乎几乎找不到任何有关如何使用它的信息。

我现在有什么选择?我已经尝试通过执行一些查询来在 Application_Start 上初始化实体框架,但这似乎并没有太大帮助,而且在 Application_Start 上执行真正的查询也非常困难,因为大多数查询使用来自当前的数据用户(尚未登录Application_Start),因此很难提前运行这些。

我考虑过创建一个 ashx 文件,该文件通过调用 API 不断轮询应用程序并使其保持活动状态。我还将应用程序池设置为“AlwaysRunning”,以便在回收应用程序池时 EF 不会重新启动。

有人对我如何解决这个问题或我可以尝试的事情有任何提示或想法吗?

提前非常感谢。我已经花了两天时间寻找可行的解决方案。

【问题讨论】:

  • 你使用什么数据库?
  • 抱歉,SQL Server。我会更新我的问题
  • 您可以尝试使用myContext.Configuration.ProxyCreationEnabled = false; 禁用代理创建。我个人禁用延迟加载,以便明确代码,所以我也myContext.Configuration.LazyLoading = false;
  • @Darren:感谢您的建议。这对延迟加载有什么影响?我刚才一直在阅读代理创建,看来这将不再(最佳)工作。有什么想法吗?
  • 延迟加载允许延迟加载相关实体。因此,您可以执行 MyUser.Account (其中 account 是另一个实体)而无需专门加载 Account (一旦您执行 .Account 数据库将再次被击中)。似乎是一个很棒的想法,但对我来说,没有什么可以替代在一次调用中准确地请求你想要的东西,而不是对数据库的一系列延迟命中。

标签: c# asp.net .net sql-server entity-framework


【解决方案1】:

Entity Framework 加速的做法有很多,我会提一些

  1. 关闭 LazyLoading(EDMX => 在任意位置右键打开文件 => 属性 => Lazy Loading Enabled 设置为 false )

  2. 使用AsNoTracking().ToList(),当您要更新时,使用Attach并将对象状态更新为EntityState.Modified

  3. 在你的桌子上使用Indexes

  4. 使用Paging,不要一次加载所有数据

  5. 将您的Edmx 拆分为多个较小的部分,只在页面中包含您需要的部分,(这会很好地影响性能)

  6. 如果您想“急切而不是懒惰”加载相关对象,请使用Include,您可以包含using System.Data.Entity 以使用 lambda 包含功能

拆分 Edmx 的示例

如果您有以下对象用于租车应用程序:CountryCityPersonCarRentGenderEngineManufacturers、..等等

现在

  • 如果您在屏幕上工作以管理 (CRUD) 人员,这意味着您不需要 Car、Rent、Manufacturer,因此创建 ManagePerson.edmx 包含(CountryCity、@987654341 @,Gender)

  • 如果您正在管理 (CRUD) 汽车,那么您不需要 (Person,City, Gender,Rent),因此您可以创建包含 (Car, Manufacturer,@ 的 ManageCar.edmx 987654346@, Engine)

【讨论】:

  • 不确定我是否明白拆分 EDMX 的意义。 AFAIK 在被召唤之前,里面什么都没有做任何事情。
  • @Darren 我确保至少第 5 点,将 EDMX 分成许多较小的 edmx 将最大限度地减少预热时间,我使用代码优先方法对此进行了测试,我有 600 多个 DBSet 的 DbContext ,我创建了大约 50 个每个 DbConext 都服务于一个单独的上下文,首次运行等待时间下降了大约 70%
  • 感谢这些建议。我正在研究其中的一些,但有一个快速的问题:使用多个 EDMX,它与使用多个图表相同吗?我可以在 edmx 文件中选择一个实体并选择“移动到新图表”。这有什么作用吗?
  • 如果您在生成的代码.cs 中查看EDMX 下面,您会发现DBSets 并继承自DBContextDBSets 的数量应该是服务于您的上下文的最小值,关于你的问题,我离测试机还很远,但正如我所提到的,如果将实体移动到另一个图表将从第一个图表生成的代码中删除 DbSet 代码,那么是,否则不是。
【解决方案2】:

Entity Framework 必须首先编译您的 LINQ 查询并将其转换为 SQL,但在此之后它会缓存它们。查询的第一次命中总是需要很长时间,但正如您之后提到的,查询将运行得非常快。

当我第一次使用 EF 时,测试人员经常提出这个问题,但是当系统上线并经常使用(并且查询被缓存)时,它就不是问题了。

有关一般加速技巧,请参阅 Hadi Hassans 的回答。

【讨论】:

  • 我知道。不过,30 秒是一段很长的时间(并尝试向您的最终用户解释)。此外,每次查询新实体时,这 30 秒的点击似乎或多或少出现。例如,我有一个组织。任何人第一次尝试查看组织列表时,都会有 30 秒的点击。还有一个出版物列表,无论组织是否已经加载,都存在完全相同的问题。加载时间各不相同,但通常每个实体大约 20 - 30 秒
  • @StevenLemmens 你可能有一个非常大的模型。这通常是一个坏主意,因为模型应该只包含与特定场景相关的内容。它应该是整个域的地图。不仅仅是为了性能,一个大模型试图覆盖所有场景,最终会映射和加载大量无用的数据
  • @StevenLemmens:这听起来不像模型,但查询创建需要您的大部分时间。由于自引入 DbContext 以来不支持预编译查询,因此您可以尝试执行(因此也编译)查询 - 不一定使用任何结果数据 - 在初始化时,或者在应用程序上没有太多负载/异步时。
猜你喜欢
  • 2011-04-22
  • 1970-01-01
  • 2020-12-03
  • 1970-01-01
  • 2017-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多