【发布时间】:2019-02-15 17:12:17
【问题描述】:
我在我的 .NET winforms 应用程序(使用 .NET 4.7.1 编译)上运行了一个分析器,它指出以下函数消耗了我应用程序 73% 的 CPU 时间,这对于一个简单的应用程序来说似乎太多了效用函数:
public static bool DoesRecordExist(string keyColumn1, string keyColumn2, string keyColumn3,
string keyValue1, string keyValue2, string keyValue3, DataTable dt)
{
if (dt != null && dt.Rows.Count > 0) {
bool exists = dt.AsEnumerable()
.Where(r =>
string.Equals(SafeTrim(r[keyColumn1]), keyValue1, StringComparison.CurrentCultureIgnoreCase) &&
string.Equals(SafeTrim(r[keyColumn2]), keyValue2, StringComparison.CurrentCultureIgnoreCase) &&
string.Equals(SafeTrim(r[keyColumn3]), keyValue3, StringComparison.CurrentCultureIgnoreCase)
)
.Any();
return exists;
} else {
return false;
}
}
这个函数的作用是传入一些键列名和匹配键值,并检查内存中c#DataTable中是否存在匹配记录。
我的应用正在处理数十万条记录,对于每条记录,必须多次调用此函数。该应用程序正在执行大量插入,并且在任何插入之前,它必须检查该记录是否已存在于数据库中。我认为针对DataTable 的内存检查比每次都返回物理数据库要快得多,所以这就是我进行内存检查的原因。每次进行数据库插入时,我都会在DataTable中进行相应的插入,以便后续检查记录是否存在准确。
所以我的问题是:有更快的方法吗?(我认为我不能避免每次都检查记录是否存在,否则我会得到重复的插入和键违规。)
编辑 #1
除了尝试我现在正在尝试的建议之外,我还想到我应该只执行一次.AsEnumerable() 并传入EnumerableRowCollection<DataRow> 而不是DataTable。你认为这会有帮助吗?
编辑#2 我刚刚做了一个受控测试,发现直接查询数据库以查看记录是否已存在比进行内存查找要慢得多。
【问题讨论】:
-
您需要对内存中的这么多记录执行所有这些操作吗? C# 不会像 SQL 那样高效。我最近遇到了一个类似的问题,一个存储过程将数十万条记录卸载到一个执行所有过滤的 C# 应用程序中。重构后,SQL 完成了大部分过滤,至少加快了 10 倍。
-
但是每次返回数据库会慢得多,不是吗?数据表已被过滤 - 那里没有不必要的记录。
-
没有想法是在 SQL 服务器上执行 WHERE 子句并在一次往返中获取结果集。您可以在实体框架、Linq2Sql 甚至 Dapper 中执行此操作。前 2 个(EF 和 L2S)将您的 LINQ 语句转换为表达式,这些表达式作为 TSQL 语句编组到服务器并在那里执行。 Dapper 希望您将查询编写为参数化 SQL。
-
@HerrimanCoder 您是否真正分析过在内存中运行查询或针对数据库运行查询之间的区别?
-
@HerrimanCoder 你会发现在数据库中运行查询,由于索引、大量内存、多核以及以 500MB/s 或更快的速度运行的数据连接的好处是指数级的比通过慢速网络连接拉取所有数据然后在没有任何索引的情况下扫描内存中的所有数据要快。如果三个键列是主键的一部分,则查询可能是即时的。
标签: c# performance linq lambda