我有下面的 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;
}
此代码有效,但比较数据表中的 10,000 条记录需要 1.24 分钟。有什么办法可以让它更快?
N
是主键和 columnName
是要比较的列。谢谢。
最佳答案
首先我会问你是否在一个简单的 for/foreach 循环中尝试过这个并比较了性能?
目前您正在创建一个新的 Enumerable,然后复制到数据表。
如果您使用 for/foreach 循环,那么您可以在同一次迭代中进行比较和复制。
您还应该查看字符串比较。目前您正在修剪然后转换为小写。这将为每个字符串的每个操作分配新的内存,因为字符串是不可变的。因此,在您的 where 语句中,您基本上每次迭代执行此操作(最多)8 次。
我也想问你是否真的需要Trim()
?一个 DT 是否有可能在字符串的前面有一个空格而另一个没有?还是比较仍然成立?除非真的需要,否则不要修剪字符串。
那么你应该使用不区分大小写的字符串比较而不是转换 ToLower
.这样会更快。根据 MS StringComparison.OrdinalIgnoreCase
性能更好。
做这些,然后比较性能,看看你有多少差异
也可以看看:
https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings
更新:
这引起了我的兴趣,所以我回去做了一些测试。
我在两个数据表中生成了 10,000 行随机(ish)数据,其中每隔一行将匹配并执行您的比较,而不是使用字符串比较的简化 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);
}
}
您的代码 = 66,000 毫秒 -> 75,000 毫秒
For 循环代码 = 12ms -> 20ms
一个显着的区别!
然后我使用 for 循环方法进行了比较,但对字符串使用了两种不同的字符串比较类型。使用我的字符串比较,与你的比较。但是我必须为此测试 100 万行,以获得显着差异。
这差异在 200 毫秒和 800 毫秒之间
因此,在这种情况下,字符串比较似乎不是主要因素。
因此,您的 Linq 查询创建数据行似乎占用了大部分时间,而不是行本身的比较。
所以切换到使用 for 循环,一切都会好起来的!
关于c# - 比较数据表的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61650083/