LINQ Group非常慢

时间:2011-08-17 17:59:21

标签: c# linq mono

以下代码需要5分钟才能在100,000行上运行。这对我来说似乎很疯狂。我做错了什么?

        var query =
            from foo in fooStuff.AsEnumerable()
            group foo by foo.Field<Int64>("FooID") into g
            select new
            {
                    FooID = g.Key,
                    FooTier = g.Min(foo => foo.Field<int>("Tier"))
            };

注意:单声道。

2 个答案:

答案 0 :(得分:5)

当您调用AsEnumerable()时,您正在实现所有实体,因此您的分组正在内存中完成。尝试删除该部分,以便在数据库级别完成分组:

var query =
        from foo in fooStuff
        group foo by foo.FooID into g
        select new
        {
                FooID = g.Key,
                FooTier = g.Min(foo => foo.Tier)
        };

答案 1 :(得分:3)

这不是直接的比较,不是Mono,但我有一些代码与6MB xml文件类似,我读入DataSet,它有30,000行,需要0.5秒,所以我不喜欢我认为是组合本身导致问题。

为了进一步诊断,我建议

  • 测试将信息读入列表所需的时间,即

    var fooList = fooStuff.AsEnumerable().ToList(); 
    
  • 测试更改查询以使用fooList而不是fooStuff所需的时间

  • 测试从select

  • 中删除FooTier = g.Min(foo =&gt; foo.Tier)所需的时间
  • 将.Field&lt;&gt;分开每个部分的groupby和time的反射,即首先从数据表中读取信息到列表中,例如

    var list2 =
    (from foo in fooStuff.AsEnumerable()
    select new { 
        FooID = foo.Field<Int64>("FooID") 
        Tier  = foo.Field<int>("Tier")
    }).ToList();
    

    然后您可以查询此列表

    var query =
    from foo in list2
    group foo by foo.FooID into g
    select new
    {
            FooID = g.Key,
            FooTier = g.Min(foo => foo.Tier)
    };
    var results = query.ToList();
    

如果此查询速度很慢,则表明mono实现GroupBy有问题。您可以通过使用类似的东西来验证

    public static Dictionary<TKey, List<TSrc>> TestGroupBy<TSrc, TKey>
     (this IEnumerable<TSrc> src, Func<TSrc,TKey> groupFunc)
    {
        var dict= new Dictionary<TKey, List<TSrc>>();

        foreach (TSrc s in src)
        {
            TKey key = groupFunc(s);
            List<TSrc> list ;

            if (!dict.TryGetValue(key, out list))
            {
                list = new List<TSrc>();
                dict.Add(key, list);
            }       
            list.Add(s);        
            }

        return dict;
}

并使用它

  var results = list2.TestGroupBy(r=>r.FooID)
      .Select(r=>  new { FooID = r.Key, FooTier = r.Value.Min(r1=>r1.Tier)} );

注意,这并不是groupby的替代品,也不能处理null键,但应该足以确定它们是否是groupby的问题(​​假设mono的Dictionary和List的实现都没问题。)

相关问题