EF核心2首先查询慢

时间:2018-06-18 16:33:35

标签: linq c#-6.0 ef-core-2.0

我在我的项目中使用EF core 2作为ORM。 我在执行此查询时遇到了这个问题:

 var query = (from droitsGeo in _entities.DroitsGeos
              join building in  _entities.Batiments
              on droitsGeo.IdPerimetre equals building.IdBatiment
              where droitsGeo.IdUtilisateur == idUser &&
              droitsGeo.IdClient == idClient &&
              building.Valide == true &&
              droitsGeo.IdNiveauPerimetre == geographicalLevel
              orderby sort ascending
              select new GeographicalModel
              {
                 Id = building.IdBatiment,
                 IdParent = building.IdEtablissement,
                 Label = building.LibBatiment,
              });

第一次执行大约需要5秒,第二次不到一秒,如下所示:

首次执行查询:

时间流逝EF:00:00:04.8562419

首次执行查询后:

经过时间EF:00:00:00.5496862

经过时间EF:00:00:00.6658079

经过时间EF:00:00:00.6176030

我使用存储过程得到相同的结果。

当我在SQL Server中执行EF生成的sql查询时,结果会在不到一秒的时间内返回。

EF Core 2出了什么问题,或者我在配置中遗漏了什么?

3 个答案:

答案 0 :(得分:3)

默认情况下,EF会跟踪您运行查询的所有实体。

第一次运行时,跟踪更改机制会启动......这就是为什么需要更长的时间。

您可以避免这种情况,尤其是在撰写查询时使用.AsNoTracking()检索集合时。

看看:

var items = DbContext.MyDbSet
    .Include(SecondObject)
    .AsNoTracking()
    .ToList();

答案 1 :(得分:1)

EF内核需要使用反射来编译LINQ查询,因此第一次查询总是很慢。 GitHub问题here

答案 2 :(得分:0)

我有一个简单的想法,可以借助存储过程以及此后的AutoMapper解决此问题。

创建一个存储过程,以返回所需的所有列,无论它们来自不同的表。一旦从存储过程中接收到数据,并且您已经在Model类之一中接收到对象,则可以使用AutoMapper将相关属性仅映射到其他类。请注意,我没有为您提供有关如何使用存储过程的教程。我给你一个例子,可能会更好地解释:

  1. 创建了一个存储过程,该存储过程从名为A,B和C的三个表中返回结果。

  2. 对应于已创建的存储过程,创建了一个名为SP_Result.cs的模型类,以映射存储过程的接收对象(在EF Core中使用存储过程时需要)

  3. 创建的“ ViewModels”具有与从每个表A,B和C返回的属性相同的属性。

  4. 此后,将使用A,B和C类的ViewModel为SP_Result创建映射配置。 CreateMap<SP_Result, ViewModel_A>(); CreateMap<SP_Result, ViewModel_B>();。我想,您将拥有一个可以代替ViewModels使用的请求和响应对象。使用AS关键字在存储过程中相应地命名属性。例如Select std_Name AS 'Name'

此映射会将各个属性映射到每个类。 AutoMapper会忽略“映射配置”中提到的两个类都不存在的属性。

如果选择的对象列表中每个对象确实都有自己的对象列表,则此方案通常将在EF中创建N + 1个查询。实际上,如果尝试使用存储过程来实现此目的,则必须创建多个查询或多次运行该存储过程(可能是循环运行),否则最终将收到笛卡尔积。