【问题标题】:Optimizing LINQ within a large datatable在大型数据表中优化 LINQ
【发布时间】:2017-05-27 12:23:20
【问题描述】:

我有一个 DataTable,它有大约 800,000 行,由 4 列组成。 StartLocation、EndLocation、距离和区域。我要做的是,对于该特定区域中的每条记录,获取“相反”记录并查看距离是否小于原始记录。此 DataTable 中的每条记录都将有一个“相反”记录。

一个示例行,它的“相反”如下所示:

StartLoc | EndLoc | Distance | Zone
 2, 1       4, 3     5         1
 4, 3       2, 1     4         1

这里的问题是当前的解决方案非常耗时且简单。下面的代码就是现在采用的策略。

public DataTable ProcessTable(DataTable _tbl)
    {
        //copy the schema to new datatable
        DataTable ProcessedTable = _tbl.Clone();

        foreach (DataRow row in _tbl.Rows)
        {
            var ReverseRow = from DataRow revRow in _tbl.Rows
                             where revRow.Field<string>("StartLoc") == row.Field<string>("EndLoc")
                             where revRow.Field<string>("EndLoc") == row.Field<string>("StartLoc")
                             where revRow.Field<string>("Zone") == row.Field<string>("Zone")
                             select revRow;

            DataRow result = ReverseRow.First<DataRow>();

            int rowDistance = row.Field<int>("Distance");
            int resultDistance = result.Field<int>("Distance");

            if (resultDistance < rowDistance)
                row["Distance"] = resultDistance;

            ProcessedTable.Rows.Add(row.ItemArray);
        }

        return ProcessedTable;
    }

我是 LINQ 新手,所以这个问题将分为 3 个部分:

  1. 有什么方法可以加快内部查询?
  2. 我能否将 foreach 循环和查询合并到一个优雅的 LINQ 行中,同时提高性能?
  3. 我认为这完全错误,需要改变我的方法吗?

【问题讨论】:

  • 欢迎。这个问题在另一个 Stack Exchange 站点上可能会做得更好。也许代码审查?任何人?祝你好运!
  • 你能考虑 StartLoc/EndLoc/Zone 的组合是唯一的吗?您可以在它们上添加主键并使用 Find 以获得良好的性能。
  • 看来你可以应用约束 StartLoc
  • 如果从数据库中获取DataTable,则应该在数据库上进行查询,而不是获取整个表。

标签: c# performance linq datatable


【解决方案1】:

尝试加入。您正在克隆整个表,这可能是速度慢的原因

       public DataTable ProcessTable(DataTable _tbl)
        {
            //copy the schema to new datatable

            var query = from r1 in _tbl.AsEnumerable()
                        from r2 in _tbl.AsEnumerable() 
                        where (r1.Field<string>("StartLoc") == r2.Field<string>("EndLoc"))
                           && (r1.Field<string>("EndLoc") == r2.Field<string>("StartLoc"))
                           && (r1.Field<string>("Zone") == r2.Field<string>("Zone")) 
                        select new { r1 = r1, r2 = r2 };

            DataTable processedTable = query.Where(x => x.r1.Field<int>("Distance") < x.r2.Field<int>("Distance"))
                                             .Select(x => x.r1)
                                             .CopyToDataTable();

            return processedTable;
        }

【讨论】:

  • 基本上就是这样。但是,为了准确起见,您可以考虑将 OP 查询中的其他条件添加到联接(还显示 OP 如何执行复合键联接)。
  • 感谢您的快速响应,我现在遇到内存不足异常。有什么建议吗?
  • 您可以尝试一次只获取一个区域。或者回到慢速方法。如果数据来自使用存储过程的 SQL Server 会更快。
  • 查询缺少必要条件,如果他以这种形式尝试,难怪它会返回废话甚至崩溃。 Ivan Stoev 已经指出了这一点。
  • OP 在 join 中有三个条件:a.StartLoc==b.EndLoca.EndLoc==b.StartLoca.Zone==b.Zone。你只有第一个。您不是将每条记录与相反的记录进行比较,而是与更多的记录进行比较。而不是 400000 对,您可以轻松拥有 400000000 对,最糟糕的是,结果不正确。
猜你喜欢
  • 1970-01-01
  • 2019-11-21
  • 2016-01-02
  • 1970-01-01
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 2019-09-24
  • 1970-01-01
相关资源
最近更新 更多