EF优化复杂的LINQ查询是否需要?

时间:2016-06-20 07:44:32

标签: c# entity-framework linq optimization iqueryable

这是一个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();

3 个答案:

答案 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);

登录到Debug或Trace

答案 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 ) })

(未经测试)