重构 GroupBy 以避免减慢对大数据集的操作



我有一个很大的集合,我需要根据两个属性获取最新的项目。第一步是根据日期属性对列表进行排序。这一切都很好,而且很快。

然后,我按两个属性对新列表进行分组,并从每个属性中获取第一项。

var one = Fisks.Where(s=>s.Havn.Id == 1).OrderByDescending(s=>s.Date);
var two = one.GroupBy(s=>new {s.Arter.Name, s.Sort});
var three = two.Select(s=>s.FirstOrDefault());

这有效,但是在大型集合上使用它时真的很慢。如何避免使用 groupBy 但仍获得相同的结果?

谢谢!

仅将 LINQ 用于第一步,然后在循环中执行第一步,可以更好地控制该过程并完全避免分组:

var query = Fisks
    .Where(f => f.Havn.Id == 1)
    .OrderByDescending(f => f.Date)
    .ThenBy(f => f.Arter.Name)
    .ThenBy(f => f.Sort);
var list = new List<Fisk>();
foreach (Fisk fisk in query) {
    if (list.Count == 0) {
        list.Add(fisk);
    } else {
        Fisk last = list[list.Count - 1];
        if (fisk.Sort != last.Sort || fisk.Arter.Name != last.Arter.Name) {
            list.Add(fisk);
        }
    }
}
一般来说,

我建议在做一些可能破坏该顺序的事情之前不要排序(例如 GroupBy 可以在 LINQ2SQL 生成的 SQL 中执行)。也尝试只订购您将要使用的东西。如果仅限制选择必填字段/属性,则可以提高查询性能。您可以摆弄此示例并改用真正的后端:

var Fisks=new[]{
    new {Havn=new{Id=1},Date=DateTime.MinValue,Arter=new{Name="A"},Sort=1,Title="A1"},
    new {Havn=new{Id=1},Date=DateTime.MinValue.AddDays(1),Arter=new{Name="A"},Sort=1,Title="A2"},
    new {Havn=new{Id=1},Date=DateTime.MinValue,Arter=new{Name="B"},Sort=1,Title="B1",},
    new {Havn=new{Id=1},Date=DateTime.MinValue.AddDays(2),Arter=new{Name="B"},Sort=1,Title="B2",},
    new {Havn=new{Id=1},Date=DateTime.MinValue.AddDays(2),Arter=new{Name="B"},Sort=1,Title="B3",},
};
var stopwatch=Stopwatch.StartNew();
var one = Fisks.Where(s=>s.Havn.Id == 1).OrderByDescending(s=>s.Date);
var two = one.GroupBy(s=>new {s.Arter.Name, s.Sort});
var three = two.Select(s=>s.FirstOrDefault());
var answer=three.ToArray();
stopwatch.Stop();
stopwatch.ElapsedTicks.Dump("elapsed Ticks");
answer.Dump();
stopwatch.Restart();
answer=Fisks
.Where(f=>f.Havn.Id.Equals(1))
.GroupBy(s=>new {s.Arter.Name, s.Sort},(k,g)=>new{
    s=g.OrderByDescending(s=>s.Date).First()//TOP 1 -> quite fast
})
.Select(g=>g.s)
.OrderByDescending(s=>s.Date) // only fully order results
.ToArray();
stopwatch.Stop();
stopwatch.ElapsedTicks.Dump("elapsed Ticks");
answer.Dump();

如果你正在使用任何SQL Server,你应该在LINQPad中检查生成的SQL。您不希望以 n+1 查询结束。对Havn.IdFisks.Date进行索引也可能有所帮助。

相关内容

  • 没有找到相关文章

最新更新