如何更好地利用linq to sql优化过滤和排序数据?

时间:2016-04-05 18:35:15

标签: c# sql-server linq linq-to-sql query-optimization

我有这个代码,我试图对病原体中报告最多的前五种血清型进行排序。让我们说有800多种血清型可能被报道。我从ObjectQuery开始,其中包含针对该病原体的所有报告。我现在需要计算按每种血清型分组的报告数量并拉回前5位。这就是我现在写的方式:

Dictionary<string, int> unsorted = new Dictionary<string, int>();

//'serotypes' is an objectquery of 800+ serotypes
foreach (LookupSerotype serotype in serotypes)   
{
    var count = Reports.Count(r => r.serotypeId == serotype.serotypeId);
    unsorted.Add(serotype.serotypeName, count);
}

// convert to list in memory in order to sort the data
var sorted = unsorted.ToList();

sorted.Sort(delegate(KeyValuePair<string, int> first, KeyValuePair<string, int> next)
{
    return first.Value.CompareTo(next.Value);
});

// reverse because the largest were sorted to the bottom
sorted.Reverse();

我可以将大多数(如果不是全部)转换为更多linq到sql,以便在查询到db时完成这些计算吗?或者是否有更快/更好的方式来提取这些信息?

具体来说,开头的第一个foreach循环时间最长,我可以使用

的帮助

2 个答案:

答案 0 :(得分:1)

如果你想用LINQ做这件事,这应该会让你接近:

var topFive = serotypes.GroupBy(s => s.serotypeName)
         .Select(s => new
         {
            SeroTypeName = s.serotypeName,
            Total = s.Count()
         }
         .OrderByDescending()
         .Take(5)
         .ToList();

此外,如果您想通过查询在服务器上完成一些工作,可以使用此SQL:

Select Top 5 serotype.serotypeName, Count(*) as Total
  from serotype
group by serotype.serotypeName
order by Total Desc

答案 1 :(得分:1)

如果serotypesReports是EF IQueryable,并假设serotype.serotypeId是PK(唯一),那么您可以使用基于{{3的单个EF查询像这样:

var query = 
    (from st in serotypes
     join r in Reports on st.serotypeId equals r.serotypeId into stReports
     order by st.serotypeName descending
     select new { st.serotypeName, reportCount = stReports.Count() }
    ).Take(5);

var result = query
    .AsEnumerable() // switch to LINQ to Objects context
    .Select(e => new KeyValuePair<string, int>(e.serotypeName, e.reportCount))
    .ToList();

唯一棘手的部分是在最终投影之前需要切换到LINQ to Objects上下文,因为EF不支持将(select)投影到没有参数构造函数的类/结构。