我正在尝试优化我们最重要的查询之一,并希望对实体框架如何翻译某些LINQ表达式有一些额外的见解。
我正在使用存储库模式,所以我的服务层(我定义我的查询)不知道实际的数据层,它(目前)限制我只使用Where语句。使用连接和其他构造可能会有所帮助,但这需要重写应用程序的某些部分。在考虑之前,我想先耗尽所有其他选项。
我提出了3个查询变体:
// Takes about 1900-2200ms for 120 records
public Expression<Func<Appointment, bool>> FilterByResources(DateTime startDate, DateTime endDate, IEnumerable<int> resourceIds)
{
// Appointments are filtered on the scheduler's start date, end date and the resources in the current page
Expression<Func<Appointment, bool>> filter = (x) => x.Assignments.Any(z => resourceIds.Contains(z.ResourceId))
&&
// Appointment starts somewhere between the start and end date
((DbFunctions.TruncateTime(x.StartDate).Value >= startDate && DbFunctions.TruncateTime(x.StartDate).Value <= endDate) ||
// Appointment started earlier than start date but ends earlier than end date
(DbFunctions.TruncateTime(x.EndDate).Value >= startDate && DbFunctions.TruncateTime(x.EndDate).Value <= endDate) ||
// Appointment starts and ends outside the boundaries
(DbFunctions.TruncateTime(x.StartDate).Value <= startDate && DbFunctions.TruncateTime(x.EndDate).Value >= endDate));
return filter;
}
备选方案#2:
// Takes about 2100ms for 120 records
public Expression<Func<Appointment, bool>> FilterByResources2(DateTime startDate, DateTime endDate, IEnumerable<int> resourceIds)
{
DateTime truncatedStartDate = startDate.Date;
DateTime truncatedEndDate = endDate.EndOfDay(); // Extension method that formats the time to 23:59:59
// Appointments are filtered on the scheduler's start date, end date and the resources in the current page
Expression<Func<Appointment, bool>> filter = (x) => x.Assignments.Any(z => resourceIds.Contains(z.ResourceId)) && (
(x.StartDate >= truncatedStartDate && x.StartDate <= truncatedEndDate) || // Appointment starts somewhere between the start and end date
(x.EndDate >= truncatedStartDate && x.EndDate <= truncatedEndDate) || // Appointment started earlier than start date but ends earlier than end date
(x.StartDate <= truncatedStartDate && x.EndDate >= truncatedEndDate) // Appointment starts and ends outside the boundaries
);
return filter;
}
备选方案3:
// Takes about 1900ms for 120 records
public Expression<Func<Appointment, bool>> FilterByResources(DateTime startDate, DateTime endDate, IEnumerable<int> resourceIds)
{
DateTime truncatedStartDate = startDate.Date;
DateTime truncatedEndDate = endDate.EndOfDay(); // Extension method that formats the time to 23:59:59
// Appointments are filtered on the scheduler's start date, end date and the resources in the current page
Expression<Func<Appointment, bool>> filter = (x) => x.Assignments.Any(z => resourceIds.Contains(z.ResourceId)) && (
(x.StartDate.CompareTo(truncatedStartDate) >= 0 && x.StartDate.CompareTo(truncatedEndDate) <= 0) || // Appointment starts somewhere between the start and end date
(x.EndDate.CompareTo(truncatedStartDate) >= 0 && x.EndDate.CompareTo(truncatedEndDate) <= 0) || // Appointment started earlier than start date but ends earlier than end date
(x.StartDate.CompareTo(truncatedStartDate) <= 0 && x.EndDate.CompareTo(truncatedEndDate) >= 0) // Appointment starts and ends outside the boundaries
);
return filter;
}
关于此查询的一点解释:此查询检索两个日期之间的多个资源(即人员)的约会列表。由于该范围,我需要包括那些先前开始,后期完成或持续时间超过范围的记录(因此是3个表达式)。
我尝试切换表达式的顺序,但结果保持稳定。对于整个网络API呼叫,平均需要1800毫秒到2200毫秒(我使用邮递员进行测试)
所以我的问题是如何优化这个查询?我认为日期比较表达式花费的时间最长,但也可能是Any / Contains组合会降低查询速度。