【问题标题】:Why is double GroupBy + ToList taking too long?为什么双重 GroupBy + ToList 花费太长时间?
【发布时间】:2017-04-23 09:03:05
【问题描述】:

我有这些疑问:

    var Data = (from ftr in db.TB_FTR
                      join mst in db.TB_MST on ftr.MST_ID equals mst.MST_ID
                      join trf in db.TB_TRF on mst.TRF_ID equals trf.ID
                      select new CityCountyType { City = ftr.CITY, County = ftr.COUNTY, Type = trf.TYPE }
                      ).OrderBy(i => i.City).ThenBy(i => i.County);

var Data2 =
    Data.GroupBy(i => new {i.City, i.County, i.Type})
        .Select(group => new {Name = group.Key, Count = group.Count()})
        .OrderBy(x => x.Name)
        .ThenByDescending(x => x.Count)
        .GroupBy(g => new {g.Name.City, g.Name.County})
        .Select(g => g.Select(g2 => 
            new {Name = new {g.Key.City, g.Key.County, g2.Name.Type}, g2.Count})).ToList();

我正在尝试获取县市相同的对象列表。但是第二个查询需要很长时间才能给出结果。我等了大约 30 分钟但没有答案,但是列表 Data 有大约 5000 条记录。如何更改这些查询,以便获得我想要的列表列表?提前致谢。

例如这个查询返回这样一个列表:

{ Name = {{ City = New York City, County  = Bronx, Type = Type A }}, Count = 4 }

{ Name = {{ City = New York City, County  = Bronx, Type = Type B }}, Count = 8 }

{ Name = {{ City = New York City, County  = Bronx, Type = Type C }}, Count = 24 }

{ Name = {{ City = New York City, County  = Manhattan, Type = Type B }}, Count = 43 }

{ Name = {{ City = New York City, County  = Manhattan, Type = Type C }}, Count = 58 }

{ Name = {{ City = Seattle, County  = King County, Type = Type D }}, Count = 43 }

{ Name = {{ City = Seattle, County  = King County, Type = Type A }}, Count = 67 }

{ Name = {{ City = Seattle, County  =    Snohomish County, Type = Type C }}, Count = 67 }

我想把这个列表分成几个这样的列表:

清单 1:

{ Name = {{ City = New York City, County  = Bronx, Type = Type A }}, Count = 4 }

{ Name = {{ City = New York City, County  = Bronx, Type = Type B }}, Count = 8 }

{ Name = {{ City = New York City, County  = Bronx, Type = Type C }}, Count = 24 }

清单 2:

{ Name = {{ City = New York City, County  = Manhattan, Type = Type B }}, Count = 43 }

{ Name = {{ City = New York City, County  = Manhattan, Type = Type C }}, Count = 58 }

清单 3:

{ Name = {{ City = Seattle, County  = King County, Type = Type D }}, Count = 43 }

{ Name = {{ City = Seattle, County  = King County, Type = Type A }}, Count = 67 }

清单 4:

{ Name = {{ City = Seattle, County  =  Snohomish County, Type = Type C }}, Count = 67 }

【问题讨论】:

  • 你不能使用 Data.Where(a => a.City.ToString() == a.County.ToString()).select(a);
  • @Biswabid 不,我想我无法很好地解释自己。请查看我的编辑。
  • 这就是我不喜欢 linq 的原因。如果您不了解它的工作原理,那可能会很糟糕。您调用的每个方法都会对返回另一个 IEnumerable 的 IEnumerable 执行 foreach。所以这些链式调用都会叠加起来,你可能会做十到十五次循环。如果你重写为单个函数,使用你自己的代码而不是 linq,你会看到性能提升
  • @peteisace 你能给我更多关于如何编写自己的代码的指导吗?
  • 好的,给我发个codepad.io链接

标签: c# list linq group-by


【解决方案1】:

可能性 1:您的数据库未编制索引以支持您的查询(where 和 join 子句)。

要找出来,获取生成的sql,查看执行计划。如果计划说嵌套循环连接 -> 聚集索引扫描,那么你就发现了问题。

可能性 2:您已经找到了 n+1 问题。

在 Linq 的GROUP BY 中,组由组键和组成员组成。然而,在大多数 SQL 实现中,GROUP BY 为您提供组键和聚合。为了获取组的成员,发出单独的查询。如果有 n 个组,则必须发出 n 个查询(+1 是原始查询)。

要查找,获取生成的sql。如果发出了一堆额外的查询,其中任何一个都说聚集索引扫描,那么您就发现了问题。

可能性 3:您实际上发出了 n^2 (~5,000,000) 个查询。

嗯,你分组了两次,所以它可能是一个双重嵌套循环。查看生成的sql就知道了。


解决所有这些问题的最简单方法是在分组之前将 5,000 条记录拉入内存。一个简单的方法是在调用GroupBy之前调用ToList

【讨论】:

  • 感谢您提供如此详细的答复。当我在GroupBy 之前调用ToList 时,它给出的答案为零。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-17
  • 1970-01-01
相关资源
最近更新 更多