比较数据表的有效方法

use*_*718 6 c# linq performance

我有下面的 c# 方法来比较两个数据表并返回不匹配的记录。

public DataTable GetTableDiff(DataTable dt1, DataTable dt2, string columnName)
{
    var StartTime = DateTime.Now;
    dt1.PrimaryKey = new DataColumn[] { dt1.Columns["N"] };
    dt2.PrimaryKey = new DataColumn[] { dt2.Columns["N"] };

    DataTable dtDifference = null;
    //Get the difference of two datatables
    var dr = from r in dt1.AsEnumerable()
             where !dt2.AsEnumerable().Any(r2 => r["N"].ToString().Trim().ToLower() == r2["N"].ToString().Trim().ToLower()
                 && r[columnName].ToString().Trim().ToLower() == r2[columnName].ToString().Trim().ToLower())
             select r;

    if (dr.Any())
    {
        dtDifference = dr.CopyToDataTable();
    }
    return dtDifference;
}
Run Code Online (Sandbox Code Playgroud)

此代码有效,但比较数据表中的 10,000 条记录需要 1.24 分钟。有什么办法可以让它更快?

N是主键,columnName是要比较的列。

谢谢。

jas*_*ith 3

首先我想问您是否在简单的 for/foreach 循环中尝试过这个并比较了性能?

目前,您正在创建一个新的 Enumerable,然后复制到数据表。如果您使用 for/foreach 循环,那么您可以在同一迭代中进行比较和复制。

您还应该查看字符串比较。目前您正在修剪然后转换为小写。由于字符串是不可变的,这将为每个字符串的每个操作分配新的内存。因此,在您的 where 语句中,每次迭代基本上会执行此操作(最多)8 次。

我还想问你真的需要吗Trim()?是否有可能一个 DT 在字符串前面有一个空格,而另一个 DT 则没有?或者比较仍然是正确的吗?除非确实需要,否则不要修剪琴弦。

那么您应该使用不区分大小写的字符串比较而不是转换ToLower。这样会更快。根据 MS 的StringComparison.OrdinalIgnoreCase说法,性能更好。

执行这些操作,然后比较性能,看看有多少差异

另请参阅: https ://learn.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings

更新:

这引起了我的兴趣,所以我回去做了一些测试。我在两个数据表中生成了 10,000 行随机数据,其中每隔一行都会匹配并执行比较,而不是使用字符串比较进行简化的 for 循环比较,如下所示:

  for (int i = 0; i < dt1.Rows.Count; i++)
  {
      if (dt1.Rows[i]["N"].ToString().Equals(dt2.Rows[i]["N"].ToString(), StringComparison.OrdinalIgnoreCase)
          && dt1.Rows[i][columnName].ToString().Equals(dt2.Rows[i][columnName].ToString(), StringComparison.OrdinalIgnoreCase))
      {
          dtDifference.Rows.Add(dt1.Rows[i].ItemArray);
      }
  }
Run Code Online (Sandbox Code Playgroud)

您的代码 = 66,000ms -> 75,000ms

For 循环代码 = 12ms -> 20ms

显着差异!

然后我使用 for 循环方法进行比较,但使用字符串的两种不同的字符串比较类型。使用我的字符串与你的字符串比较。但我必须为此测试 100 万行,才能获得显着差异。

相差 200 毫秒到 800 毫秒

所以在这种情况下,字符串比较似乎不是主要因素。

因此,创建数据行的 Linq 查询似乎花费了大部分时间,而不是行本身的比较。

所以改用 for 循环吧,一切都会好起来的!