EF 需要优化复杂的 LINQ 查询吗?
EF optimize complex LINQ query required?
这是一个 LINQ 查询,用于使用 Entity Framework 7 从数据库中检索数据。有几个 .Where(x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First()
。有没有办法优化这个查询?是否需要这样做或 EF 自己优化它?
var bs = await db.Building.Include(x => x.CollectedMaterial)
.Where(x => x.MaterialIDLocked == BuildingDataLockType.LockedByBuildingInfoSource)
.Where(x => x.CollectedMaterial.Count > 0)
.Where(
x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().Repeats >= firstRepeatsCount)
.Where(x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().MaterialID != x.MaterialID)
.ToListAsync();
据我所知,您不应使用多个 where 子句来过滤列表,而应将条件放在单个 where 子句中。
编辑:是的,似乎也可以使用 multiple where clauses
提示:尝试过滤掉查询本身中的所有数据,不要通过获取不必要的数据来过滤内存中的对象,甚至可能是不必要的字段您可以使用投影操作来仅 select必填字段。
答案here too say so, I usually go for a balance b/w readability and performance you should try to evaluate how much performance improvement would be required, also try Visual Studio Profiler它有记忆,cpu抽样等
如果您在 get 方法中编写该代码,那么您可以在 DbSet 上使用 AsNoTracking 方法,这将提高性能,因为 Entity Framework 不会使用它创建的跟踪对象来跟踪它默认。
在您的 DbContext 对象上使用 Database.Log 属性 来记录生成的 SQL 查询,并通过更改代码来查看哪个查询看起来很复杂,这将对您有所帮助。
您可以 context.Database.Log = Console.WriteLine;
登录控制台应用程序
您可以以 context.Database.Log = message => Trace.WriteLine(message);
的身份登录任何其他应用程序进行调试或跟踪
由于您正在使用 IQueryable
,您可以根据需要将 .Where()
条件链接起来,您所创建的只是一个表达式树,稍后将对其进行评估。
当您实际从数据库中检索数据时(如您的示例 ToList()
),EF 然后创建实际优化的 SQL 查询。
然后视情况而定..你能做的最好的事情是对你的数据库进行 运行 SQL 分析器并捕获并查看 实际生成的 查询EF.
据我所知,实体会优化所有内容,直到实现实际的数据库调用。在您的情况下,即调用 .ToListAsync
时。
编辑:看到 评论,看来您应该合并所有查询。不过,如果可以,请考虑使用变量定义。
关于优化,可能要合并
.Where( x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().Repeats >= firstRepeatsCount)
.Where( x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().MaterialID != x.MaterialID)
到
.Where( x => {
var firstRepeats = x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().Repeats;
return ( firstRepeats.Repeats >= firstRepeatsCount &&
firstRepeats.MaterialID != x.MaterialID ) })
(虽然未经测试)
这是一个 LINQ 查询,用于使用 Entity Framework 7 从数据库中检索数据。有几个 .Where(x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First()
。有没有办法优化这个查询?是否需要这样做或 EF 自己优化它?
var bs = await db.Building.Include(x => x.CollectedMaterial)
.Where(x => x.MaterialIDLocked == BuildingDataLockType.LockedByBuildingInfoSource)
.Where(x => x.CollectedMaterial.Count > 0)
.Where(
x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().Repeats >= firstRepeatsCount)
.Where(x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().MaterialID != x.MaterialID)
.ToListAsync();
据我所知,您不应使用多个 where 子句来过滤列表,而应将条件放在单个 where 子句中。
编辑:是的,似乎也可以使用 multiple where clauses
提示:尝试过滤掉查询本身中的所有数据,不要通过获取不必要的数据来过滤内存中的对象,甚至可能是不必要的字段您可以使用投影操作来仅 select必填字段。
答案here too say so, I usually go for a balance b/w readability and performance you should try to evaluate how much performance improvement would be required, also try Visual Studio Profiler它有记忆,cpu抽样等
如果您在 get 方法中编写该代码,那么您可以在 DbSet 上使用 AsNoTracking 方法,这将提高性能,因为 Entity Framework 不会使用它创建的跟踪对象来跟踪它默认。
在您的 DbContext 对象上使用 Database.Log 属性 来记录生成的 SQL 查询,并通过更改代码来查看哪个查询看起来很复杂,这将对您有所帮助。
您可以 context.Database.Log = Console.WriteLine;
您可以以 context.Database.Log = message => Trace.WriteLine(message);
由于您正在使用 IQueryable
,您可以根据需要将 .Where()
条件链接起来,您所创建的只是一个表达式树,稍后将对其进行评估。
当您实际从数据库中检索数据时(如您的示例 ToList()
),EF 然后创建实际优化的 SQL 查询。
然后视情况而定..你能做的最好的事情是对你的数据库进行 运行 SQL 分析器并捕获并查看 实际生成的 查询EF.
据我所知,实体会优化所有内容,直到实现实际的数据库调用。在您的情况下,即调用 .ToListAsync
时。
编辑:看到
关于优化,可能要合并
.Where( x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().Repeats >= firstRepeatsCount)
.Where( x => x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().MaterialID != x.MaterialID)
到
.Where( x => {
var firstRepeats = x.CollectedMaterial.OrderByDescending(y => y.Repeats).First().Repeats;
return ( firstRepeats.Repeats >= firstRepeatsCount &&
firstRepeats.MaterialID != x.MaterialID ) })
(虽然未经测试)