在C#.net中处理巨大数据表的有效方法

时间:2011-10-10 20:19:24

标签: c# linq datatable

我有一个巨大的dataTable(大约500k-600k行)。我想根据某些特定列计算行数。 例如:我有3列名称ID,类型和值。我想根据'Type'计算'value'列。我使用DataRow Filter完成了它 - 首先获取唯一的'ID',然后为每个'type'计算值。这种逻辑非常复杂,需要更长的时间来处理。我在LINQ方面不是很好,所以我想知道我是否可以使用LINQ或其他任何方式做得更好?

数据表:

ID       type      value  
--------------------------------
2         100         5

2         100         6

2         200         10

3         200         8

3         200         9

4         100         10

4         200         15

我正在寻找的输出是:

ID     Type          Value

2       100            11

2       200            10

3       200            17

4       100            10

4       200            15

4 个答案:

答案 0 :(得分:5)

我认为你所寻找的是这样的。显然,在我使用<int>的地方,您需要根据需要替换适当的类型。

var output = from row in table.AsEnumerable()
             let id = row.Field<int>("ID")
             let type = row.Field<int>("type")
             group row by new { id, type } into grp 
             select new 
             {
                 ID = grp.Key.id,
                 Type = grp.Key.type,
                 Value = grp.Sum(r => r.Field<int>("value"))
             };

这将导致相当简单的代码,但它不应该比一个编写良好的循环更具有效率(当然,如果你可以卸载它相反,这对数据库而言,通常会更好。)但是,所有事情都是平等的,Linq代码非常优化和高效。如果您对效率有疑问,衡量。运行现有代码(如果有的话)和答案代码,看看你的位置。

答案 1 :(得分:4)

为什么不在SQL中呢?

select id, type, sum(value) from TABLE group by id, type

答案 2 :(得分:3)

VB.NET(如果有人感兴趣的话):

Dim groups = From r In tbl
             Group r By IDTypes = _
             New With {Key .ID = CInt(r("ID")), _
                       Key .Type = CInt(r("Type"))}
                  Into Group
             Select New With { _
                    .ID = IDTypes.ID, _
                    .Type = IDTypes.Type, _
                    .Value = Group.Sum(Function(grpRow) (CInt(grpRow("Value"))))}

这是测试数据:

Dim tbl As New DataTable
Dim row As DataRow
Dim rnd As New Random(Now.Millisecond)
tbl.Columns.Add(New DataColumn("ID", GetType(Int32)))
tbl.Columns.Add(New DataColumn("Type", GetType(Int32)))
tbl.Columns.Add(New DataColumn("Value", GetType(Int32)))
For i As Int32 = 1 To 1000000
    row = tbl.NewRow
    row("ID") = 2 * Rnd.Next(0, 6)
    row("Type") = 100 * Rnd.Next(0, 6)
    row("Value") = 5 * Rnd.Next(0, 11)
    tbl.Rows.Add(row)
Next

1.000.000行的时间测量:

watch.Start()
Dim execute = groups.Any()
watch.Stop()
Console.WriteLine(String.Format("{0:00}:{1:00}:{2:00}.{3:00}", _
                                        watch.Elapsed.Hours, _
                                        watch.Elapsed.Minutes, _
                                        watch.Elapsed.Seconds, _
                                        watch.Elapsed.Milliseconds / 10))

结果(在2,26 GHZ Xeon,24GB):

  1. 00:00:00.61
  2. 00:00:00.58
  3. 00:00:00:63
  4. 对于1.000.000行的

    ~600毫秒分组+累计到~36“ID类型”

答案 3 :(得分:0)

假设您正在寻找某种分组,在值列上使用某种类型的聚合,您可以执行以下操作:

DataTable table = new DataTable();

var results = from row in table.AsEnumerable()
              group row by new { Type = row.Field<int>("Type") } into groups
              select new
              {
                  Type = groups.Key.Type,
                  TotalValue = groups.Sum(x => x.Field<int>("Value"))
              };