【问题标题】:Join two tables using linq, and fill a Dictionary of them使用 linq 连接两个表,并填写它们的字典
【发布时间】:2013-06-24 05:33:13
【问题描述】:

我一直在寻找如何连接两个表(Data 和 DataValues,一对多)并填充类型为 的字典。

Data(s) 的记录可能有数千条(例如 500,000 条或更多),每个 Data 可能有 10 到 20 个 DataValue,这使得查询更加繁重,因此性能在这里非常重要。

这是我写的代码:

// Passed via the arguments, for example, sensorIDs would contain:
int[] sensorIDs = { 0, 1, 2, 3, 4, 5, 6, 17, 18 };
Dictionary<Data, List<DataValue>> dict = new Dictionary<Data, List<DataValue>>();

foreach (Data Data in dt.Datas)
{
    var dValues = from d in dt.Datas
                        join dV in dt.DataValues on d.DataID equals dV.DataID
                        where (SensorIDs.Contains(dV.SensorID))
                        select dV;
    dict.Add(Data, dValues.ToList<DataValue>());
}

但是这种方法存在严重的性能问题并且需要很长时间才能执行。 不确定我是否需要使用 SQL 视图。有什么建议吗?

【问题讨论】:

  • 你的数据表有多大?
  • 每天大约1200条记录(仅用于Data),每个数据可能有5到18个DataValue。 “数据”表的当前行数为 125,361
  • 顺便说一句,您的查询也不正确,您应该在dt.DataValues 上进行选择,并在您的where 语句中包括检查Data.DataID == dV.DataID

标签: c# sql-server performance linq linq-to-sql


【解决方案1】:

您查询的次数太多了。您可以在一个查询中完成此操作。

var dict = (from d in dt.Datas
            join dV in dt.DataValues on d.DataID equals dv.DataID
            where SensorIDs.Contains(dv.SensorID)
            select new { d, dV }).ToDictionary(o => o.d, o => o.dV.ToList());

在您的 foreach 循环中,您正在获取所有 Data 并且对于它们中的每一个,您都在做同样的事情。

编辑:现在还不是很清楚,但我认为您只想加入 SensorIDs 数组中的 DataValues。在这种情况下:

var dict = (from d in dt.Datas
            let dV = (from dataValue in dt.DataValues
                      where SensorIDs.Contains(dataValue.SensorID) &&
                            dataValue.DataID = d.DataID
                      select dataValue)
            select new { d, dV }).ToDictionary(o => o.d, o => o.dV.ToList());

【讨论】:

  • 对于DataDataValueSeonsorID 在他的模型和/或数据库中如何相互关联,我无法确定。但是在实体框架中,带有数组的Contains 转换为IN (.. the values in the array ..) 语句。因此,除非他正在使用 Contains 的数组非常大,否则它对性能的影响非常小。
  • 嗯,谢谢,但是返回类型是 类型的字典,而我想要 >(注意列表!)
  • @SimonBelanger 是的,没错,但是如何将数据表加入 Ints 数组?
  • 加入数组的目的是什么?在任何情况下,您都不能同时加入服务器和应用程序中的内容。如果你这样做了,整个表将下来做一个内存连接
  • @SimonBelanger 非常感谢。效果很好,性能很好:)
【解决方案2】:

在这种情况下,您不需要 foreach 循环,您可以使用 group join 直接从 linq 创建字典,这应该会给您带来更好的性能。

dict=(from DataValue d in dt.DataValues
           where sensorIDs.Contains(d.SensorID)
       group d by d.DataID 
           into datavalues
       join data in dt.Datas 
           on datavalues.Key equals data.DataId
       select new { 
         Key = data, 
         Value = datavalues
       }).ToDictionary(a=>a.Key,a=>a.Value.ToList());

或者你可以使用 linq 表达式方法

dict = dt.DataValues.Where(d=>sensorIDs.Contains(d.SensorID))
            .GroupBy(a=>a.DataID)
             .Join(dt.Datas,a=>a.Key,a=>a.DataId,
                    (a,b)=>new{Key=b,Value=a.ToList()})
        .ToDictionary(a=>a.Key,a=>a.Value);

【讨论】:

    【解决方案3】:

    您不需要 foreach 循环。一般尝试这样的事情:

    var columns = dt.Columns.Cast<DataColumn>();
    dt.AsEnumerable().Select(dataRow => columns.Select(column => 
                         new { Column = column.ColumnName, Value = dataRow[column] })
                     .ToDictionary(data => data.Column, data => data.Value));
    

    另外,请考虑阅读以下内容:http://blogs.teamb.com/craigstuntz/2010/01/13/38525/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 2011-12-15
      • 1970-01-01
      • 2015-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多