[英]Optimizing a slow LINQ query
I have a LINQ query that I am having trouble optimizing and takes about 5.5 seconds to run. 我有一个LINQ查询,我无法优化,大约需要5.5秒才能运行。 I am using a view called StaffingResourceData and a table called StaffingForecasts.
我正在使用一个名为StaffingResourceData的视图和一个名为StaffingForecasts的表。
Each StaffingResource has a ResourceId, a Division, and a Type. 每个StaffingResource都有一个ResourceId,一个Division和一个Type。 A StaffingForecast has a ResourceId, Project, Date (represents a Monday of a week), Hours.
StaffingForecast有一个ResourceId,Project,Date(表示一周的星期一),Hours。 A StaffingResource can have 0-many StaffingForecasts.
StaffingResource可以有0多个StaffingForecasts。
For each StaffingResource, I need a list of their total forecasted hours for the next 12 weeks. 对于每个StaffingResource,我需要一份他们未来12周的总预测时间列表。 Here is what I have right now:
这就是我现在所拥有的:
// Get list of dates
var dates = new List<DateTime>();
var start = Utilities.GetStartOfWeek(DateTime.Today);
for (var i = 0; i < 12; i++)
{
dates.Add(start.AddDays(i * 7));
}
var end = dates[11];
// Get resources
var resources = (from r in context.StaffingResourceDatas
where r.EmployeeId != null
&& !exclusionList.Contains(r.ResourceTitleId)
join f in context.StaffingForecasts.Where(x => x.Date >= start && x.Date <= end) on r.ResourceId equals f.ResourceId into g1
from f in g1.DefaultIfEmpty()
group new { f.Date, f.Hours } by r into g2
select new ChartResourceModel
{
ResourceId = g2.Key.ResourceId,
Division = g2.Key.ResourceDivision,
Type = g2.Key.ResourceType,
Dates = dates.Select(d => new ChartDateModel
{
Date = d,
Available = (g2.Where(f => f.Date == d).Any() ? g2.Where(f => f.Date == d).Sum(f => f.Hours) : 0) < 24
}).ToList()
})
.ToList();
Any ideas on how I could speed this up? 关于如何加快速度的任何想法?
Avoid using Contains
. 避免使用
Contains
。 It degrades performance heavily. 它严重降低了性能。 See this post
看这篇文章
ToList()
is a command to execute your query. ToList()
是执行查询的命令。 Till you call ToList()
method, linq query is not started as linq has a feature called deferred execution . 直到调用
ToList()
方法,linq查询才会启动,因为linq具有一个名为延迟执行的功能。 So if you call ToList()
, you start some real operations with Databaseof files. 因此,如果您调用
ToList()
,则可以使用Databaseof文件启动一些实际操作。
turn off change-tracking and identity-management (for example, ObjectTrackingEnabled in LINQ-to-SQL) 关闭变更跟踪和身份管理(例如,LINQ-to-SQL中的ObjectTrackingEnabled)
using (YourDataContext dataContext = new YourDataContext()) { dataContext.ObjectTrackingEnabled = false; //Your code }
.AsNoTracking()
. .AsNoTracking()
。 The extensive description can be seen here. After playing around with it for awhile, I was able to get the loading time down from 5.5 seconds to 1.5 seconds. 在玩了一段时间后,我能够将加载时间从5.5秒降低到1.5秒。 Here is what I came up with:
这是我想出的:
// Get resources
var resources = (from r in
(from r in context.StaffingResourceDatas
where r.EmployeeId != null
&& !exclusionList.Contains(r.ResourceTitleId)
join f in context.StaffingForecasts on r.ResourceId equals f.ResourceId
group f by r into g
select new
{
Resource = g.Key,
Forecasts = g.Where(f => f.Date >= start && f.Date <= end && f.StaffingPotentialProject == null).ToList()
}).ToList()
group r.Forecasts by r.Resource into g
select new ChartResourceModel
{
ResourceId = g.Key.ReportsToId,
Division = g.Key.ResourceDivision,
Type = g.Key.ResourceType,
Dates = dates.Select(d => new ChartDateModel
{
Date = d,
Available = (g.SelectMany(f => f.Where(x => x.Date == d)).Sum(x => x.Hours)) < 24
}).ToList()
}).ToList();
It seems like the best way is to just get all the data you need and calling .ToList() without trying to do anything fancy and then performing any extra operations on that data. 看起来最好的方法是获取所需的所有数据并调用.ToList()而不尝试做任何奇特的事情,然后对该数据执行任何额外的操作。
For start, try to avoid ".ToList()" unless everything is done, because when you fire ".ToList()", result is being materialized, which you don't want if there is a lot of data and you want to do more query operations on that data. 首先,尽量避免“。ToList()”,除非一切都已完成,因为当您触发“.ToList()”时,结果正在实现,如果有大量数据并且您想要对该数据执行更多查询操作。
So, try with IQueryable properties, so you can at least get data much faster and then do some operation on it. 因此,尝试使用IQueryable属性,这样您至少可以更快地获取数据,然后对其进行一些操作。
And of course, check what is with query/queries you are sending to SQL. 当然,检查您要发送给SQL的查询/查询是什么。 Maybe columns you are searching are not properly indexed(!?) or you don't have any indexes in tables (?).
也许你正在搜索的列没有正确编入索引(!?),或者表中没有任何索引(?)。
I would put my bet on a simple subquery, "naturally" representing the information needed, like this 我会把我的赌注放在一个简单的子查询上,“自然地”代表所需的信息,就像这样
var query =
from r in context.StaffingResourceDatas
where r.EmployeeId != null && !exclusionList.Contains(r.ResourceTitleId)
select new ChartResourceModel
{
ResourceId = r.ResourceId,
Division = r.ResourceDivision,
Type = r.ResourceType,
Dates = dates.Select(d => new ChartDateModel
{
Date = d,
Available = context.StaffingForecasts.Where(f =>
f.ResourceId == r.ResourceId && f.Date == d).Sum(f => f.Hours) < 24
}).ToList()
};
var sqlQuery = query.ToString();
var result = query.ToList();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.