过滤大集合

时间:2017-05-26 12:31:50

标签: c# performance linq asp.net-mvc-4

我正在围绕 3000 员工&每个员工循环一个月的所有日期

我已从Db预加载了一个列表ShiftDetails以提高性能。

foreach (var item in lstEmp)
{
  while (fDate <= ToDate)
  {
    var employeeShifts = ShiftDetails
      .Where(a => a.EmployeeId == item.Id && a.ShiftDate == fDate)
      .Select(a => a)
      .FirstOrDefault();
  }
}

当我使用Profiler检查性能时,上面一行代码正在耗费大量时间。

有什么办法可以提高代码的性能吗?

我搜索过&amp;发现字典最适合解决这个问题,但它们应该有唯一的密钥,在我的情况下,我没有列表中的任何唯一列。

3 个答案:

答案 0 :(得分:0)

从我看到的EmployeeId&amp;组合ShiftDate可能是您唯一的密钥。

尝试使用以下内容手动创建密钥:

var key = EmployeeId.ToString() + " - " + a.ShiftDate.ToString();

然后你的搜索就像这样一行:

if (myDictionary.ContainsKey(key))
{
//  .. do your logic here
}

答案 1 :(得分:0)

这个解决方案怎么样:

foreach (var item in lstEmp)
{
  var employeeShifts = ShiftDetails
      .Where(a => a.EmployeeId == item.Id && isInDate(a.ShiftDate))
      .Select(a => a)
      .FirstOrDefault();
}

代码中的任何其他位置:

public bool isInDate(date start, date end, date dateFromUserProperty){
    //if dateFromUserProperty is within the range (start - end date) return true, 
    //else return false
}

你能解释一下这个项目是什么吗?您是否尝试在项目集合和用户集合之间建立交集?

答案 2 :(得分:0)

我会将您的操作分成两个程序:

  • 按每个EmployeeId

  • 的班次进行过滤
  • 根据过滤后的班次,请先按ShiftDate

  • 进行过滤

在while循环之外按EmployeeId进行过滤更快,因为我们只计算此结果一次,而不是每个月中的每个日期。将结果保存为List也会给我们带来轻微的性能提升,因为我们可以利用List.Find(返回给定谓词的第一个匹配值,并针对List优化) Where / FirstOrDefault

foreach (var item in lstEmp)
{
    var shiftsByEmployeeId = ShiftDetails.Where(a => a.EmployeeId == item.Id).ToList();
    while (fDate <= ToDate)
    {
        var employeeShifts = shiftsByEmployeeId.Find(a => a.ShiftDate == fDate);
    }
}