[英]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();
AFAIK,您不应使用多个where子句来过滤列表,而应将条件放在单个where子句中。
编辑:是的,同时使用多个where子句似乎也很好
提示:尝试过滤掉查询本身中的所有数据,而不是通过获取不必要的数据来过滤内存中对象,即使是不必要的字段,也可以使用投影操作仅选择必需的字段。
这里的答案也是如此,我通常会在黑白可读性和性能之间取得平衡,您应该尝试评估需要多少性能改进,还尝试使用Visual Studio Profiler,它具有内存,cpu采样等。
如果您使用get方法编写该代码,则可以在DbSet上使用AsNoTracking方法,这将提高性能,因为实体框架不会使用默认情况下创建的跟踪对象对其进行跟踪。
使用DbContext对象上的Database.Log属性记录生成的SQL查询,并通过更改代码来查看看起来复杂的查询,这将对您有所帮助。
您可以作为context.Database.Log = Console.WriteLine;
登录Console App context.Database.Log = Console.WriteLine;
您可以登录任何其他应用程序作为context.Database.Log = message => Trace.WriteLine(message);
来调试或跟踪context.Database.Log = message => Trace.WriteLine(message);
由于您正在使用IQueryable
,因此可以根据需要链接.Where()
条件,因此您创建的只是一个表达式树,稍后将对其进行评估。
当您实际从DB中检索数据时(例如在您的示例ToList()
),EF然后将创建实际的优化SQL查询。
然后,这取决于..最好的办法是对数据库运行SQL事件探查器,并捕获并查看EF 实际生成的查询。
AFAIK,实体会优化所有内容,直到实现实际的db调用为止。 在您的情况下,那就是对.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 ) })
(不过未经测试)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.