加快linq组总和查询

时间:2013-11-13 15:06:56

标签: c# asp.net linq entity-framework

我有一个查询,处理从各种表中提取的大约500条记录,分组然后总结(如果这是一个单词)到工作报告中。一切正常,但运行这一个报告大约需要30秒,我收到了用户的投诉。

有问题的程序就是这个:

    public static List<LabourEfficiencies> GetLabourEfficienciesByTimeSheet(DateTime dateFrom, DateTime dateTo)
    {
        CS3Entities ctx = new CS3Entities();

        //get all relevant timesheetline items
        var tsItems = from ti in ctx.TimeSheetItems
                      where ti.TimeSheetHeader.Date >= dateFrom && ti.TimeSheetHeader.Date <= dateTo && ti.TimeSheetHeader.TimeSheetCategory != "NON-PROD"
                      select new TimesheetLine
                      {
                          TimesheetNo = ti.TimeSheetNo,
                          HoursProduced = ti.HoursProduced,
                          HoursProducedNet = ti.HoursProducedNet,
                          ItemID = ti.ItemID,
                          ProcessID = ti.ProcessID,
                          ProcessDuration = ti.ProcessDuration,
                          DowntimeHours = 0M
                      };

        //get all relevant downtimeline items
        var tsDownT = from dt in ctx.DowntimeItems
                      where dt.TimeSheetHeader.Date >= dateFrom && dt.TimeSheetHeader.Date <= dateTo && dt.TimeSheetHeader.TimeSheetCategory != "NON-PROD"
                      select new TimesheetLine
                      {
                          TimesheetNo = dt.TimeSheetNo,
                          HoursProduced = 0M,
                          HoursProducedNet = 0M,
                          ItemID = "",
                          ProcessID = "",
                          ProcessDuration = 0M,
                          DowntimeHours = dt.DowntimeHours
                      };

        //combine them into single table
        var tsCombi = tsItems.Concat(tsDownT);

        var flatQuery = (from c in tsCombi
                        join th in ctx.TimeSheetHeaders on c.TimesheetNo equals th.TimeSheetNo
                        select new
                                   {
                                       th.TimeSheetNo,
                                       th.EmployeeNo,
                                       th.TimeSheetCategory,
                                       th.Date,
                                       c.HoursProduced,
                                       c.ProcessDuration,
                                       th.HoursWorked,
                                       c.HoursProducedNet,
                                       c.DowntimeHours,
                                       c.ItemID
                                       });

        //add employee details & group by timesheet no (1 line per timesheet no)
        //NB. FnTlHrs checks whether there are any indirect hrs & deducts them if there are
        var query =  flatQuery.GroupBy(f => f.TimeSheetNo).Select(g => new LabourEfficiencies
                                                                            {
                                                                                Eno = g.FirstOrDefault().EmployeeNo,
                                                                                Dept =g.FirstOrDefault().TimeSheetCategory,
                                                                                Date = g.FirstOrDefault().Date,
                                                                                FnGrHrs =g.Where(w =>w.TimeSheetCategory == "FN" &&!w.ItemID.StartsWith("090")).Sum(h => h.HoursProduced),
                                                                                FnTlHrs =g.Where(w =>w.ItemID.StartsWith("090")).Sum(h => h.ProcessDuration) >0? (g.FirstOrDefault(w =>w.TimeSheetCategory =="FN").HoursWorked) -(g.Where(w =>w.ItemID.StartsWith("090")).Sum(h =>h.ProcessDuration)): g.FirstOrDefault(w =>w.TimeSheetCategory =="FN").HoursWorked,
                                                                                RmGrHrs =g.Where(w =>w.TimeSheetCategory == "RM").Sum(h => h.HoursProduced),RmGrHrsNet =g.Where(w =>w.TimeSheetCategory == "RM").Sum(h => h.HoursProducedNet),
                                                                                RmTlHrs =g.FirstOrDefault(w =>w.TimeSheetCategory == "RM").HoursWorked,
                                                                                MpGrHrs =g.Where(w =>w.TimeSheetCategory =="MATPREP").Sum(h => h.HoursProduced),
                                                                                MpTlHrs =g.FirstOrDefault(w =>w.TimeSheetCategory =="MATPREP").HoursWorked,
                                                                                DtHrs = g.Sum(s => s.DowntimeHours),
                                                                                Indirect =g.Where(w =>w.ItemID.StartsWith("090")).Sum(h => h.ProcessDuration)
                                                                            });

        return query.ToList();
    }

前几位只是收集数据,它是最后一个查询,它是程序的“肉”并占用时间。

我很确定我做了一些可怕的事情,因为它吐出来的SQL很可怕,但对于我的生活,我看不出如何改进它。

任何提示都非常赞赏。

戈登

1 个答案:

答案 0 :(得分:1)

您的表达式在IQueriable编译和SQL服务器查询优化中都得到优化,即使这样也需要很长时间。很可能您没有执行计划所需的列索引更快。将渲染的SQL表达式复制/粘贴到SSMS,运行它并查看实际计划。如果需要,优化数据库结构(放置索引)。否则,你得到了非常大的数据,这使得进程变慢。