这是一个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();
答案 0 :(得分:2)
AFAIK你不应该使用multiple where子句来过滤掉一个列表,而是将条件放在一个where子句中。
编辑:是的,似乎也可以使用multiple where clauses提示:尝试过滤掉查询本身中的所有数据,不要通过获取不必要的数据来过滤内存中对象,甚至可能使用投影操作来选择所需字段的不必要字段。
答案here也是如此,我通常会考虑平衡黑白可读性和性能,你应该尝试评估需要多少性能提升,同时尝试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);
答案 1 :(得分:1)
由于您正在使用IQueryable
,因此您可以根据需要链接.Where()
条件,您创建的只是一个表达式树,稍后将对其进行评估。
当您实际从数据库中检索数据时(如示例中的ToList()
),EF会创建实际优化的SQL查询。
然后它取决于......您可以做的最好的事情是针对您的数据库运行SQL分析器并捕获并查看EF的实际生成的查询。
答案 2 :(得分:1)
AFAIK,实体优化所有内容,直到实现实际的db调用。在您的情况下,即调用.ToListAsync
时。
编辑:看到this评论,似乎您应该合并所有查询。如果可以,请考虑使用变量defition。
关于优化,您可能想要合并
.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 ) })
(未经测试)