C# 如何在csv导入列表上加速linq查询
我的任务是将170万条记录与csv文件中传递给我的一些结果进行匹配 下面代码的一点背景,我有两个列表 证书包含5个属性,ID相当于PK 包含证书列表中应包含的ID列表的订单 我需要将两者匹配起来,并对找到的证书对象执行一些操作C# 如何在csv导入列表上加速linq查询,c#,linq,csv,large-data,C#,Linq,Csv,Large Data,我的任务是将170万条记录与csv文件中传递给我的一些结果进行匹配 下面代码的一点背景,我有两个列表 证书包含5个属性,ID相当于PK 包含证书列表中应包含的ID列表的订单 我需要将两者匹配起来,并对找到的证书对象执行一些操作 foreach (Classes.CertOrder.IDS OrderUnitID in Order.AllIDs) { var Cert = (from C in Certs where
foreach (Classes.CertOrder.IDS OrderUnitID in Order.AllIDs)
{
var Cert = (from C in Certs where C.ID.ToUpper() == OrderUnitID.ID.ToUpper() select C).FirstOrDefault();
if (Cert != null)
{
Output.add(Cert)
OrderUnitID.fulfilled = true;
}
}
这段代码可以工作,但它的速度非常慢(我猜这是由于记录的数量),有什么方法可以加快速度吗
编辑到添加,希望能够将数据添加到SQL server以运行查询,但是数据不允许离开正在处理文件的工作站,甚至不允许以未加密的形式接触磁盘
结合下面的有用答案,我已将输出更改为基于列表,按ID对两个列表进行预排序,现在处理需要几秒钟而不是几小时!谢谢堆栈溢出 为什么数据库查找更快? 原因之一是索引 您可以使用创建内存中列表的索引
然后对每个循环使用并行程序来加快速度。从
证书创建字典:
var certsMapping = Certs
.ToDictionary(_ => _.ID.ToUpper());
foreach (Classes.CertOrder.IDS OrderUnitID in Order.AllIDs)
{
if (certMapping.TryGetValue(OrderUnitID.ID.ToUpper(), out var cert))
{
Output.add(cert);
OrderUnitID.fulfilled = true;
}
}
在公认答案的基础上再扩展一些其他选项。OrdinalingOrecase提供了最佳的单线程性能,而并行化则提供了最佳的总体性能
class Item { public string Id { get; set; } }
class Program
{
private static Random rng = new Random();
private static string characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static void Main(string[] args)
{
var list = Enumerable.Range(1, 2_700_000)
.Select(x => string.Join("", Enumerable.Range(5, rng.Next(20)).Select(y => characters[rng.Next(0, characters.Length)])))
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(x => new {Order = rng.Next(), Item = new Item {Id = x }})
.OrderBy(x => x.Order)
.Select(x => x.Item)
.ToList();
Console.WriteLine("Master List Size: {0}", list.Count);
var matches = list.Take(350_000).Select(x => x.Id).ToList();
Console.WriteLine("Matches List Size: {0}", matches.Count);
var dict = list.ToDictionary(x => x.Id, x => x, StringComparer.CurrentCultureIgnoreCase);
var results = new List<Item>();
var sw = new Stopwatch();
Console.WriteLine("CurrentCultureIgnoreCase Elapsed Time (avg): {0}",
Enumerable.Range(1, 10).Select(x =>
{
sw.Start();
foreach (var m in matches)
if (dict.TryGetValue(m, out var item))
results.Add(item);
sw.Stop();
var t = sw.ElapsedMilliseconds;
sw.Reset();
return t;
}).Average());
dict = list.ToDictionary(x => x.Id.ToUpper(), x => x);
Console.WriteLine("ToUpper() Elapsed Time (avg): {0}",
Enumerable.Range(1, 10).Select(x =>
{
sw.Start();
foreach (var m in matches)
if (dict.TryGetValue(m.ToUpper(), out var item))
results.Add(item);
sw.Stop();
var t = sw.ElapsedMilliseconds;
sw.Reset();
return t;
}).Average());
dict = list.ToDictionary(x => x.Id, x => x, StringComparer.OrdinalIgnoreCase);
Console.WriteLine("OrdinalIgnoreCase Elapsed Time (avg): {0}",
Enumerable.Range(1, 10).Select(x =>
{
sw.Start();
foreach (var m in matches)
if (dict.TryGetValue(m, out var item))
results.Add(item);
sw.Stop();
var t = sw.ElapsedMilliseconds;
sw.Reset();
return t;
}).Average());
}
}
var cDict = new ConcurrentDictionary<string,Item>(dict);
var cResults = new ConcurrentBag<Item>();
Console.WriteLine("Parallel Elapsed Time (avg): {0}",
Enumerable.Range(1, 10).Select(x =>
{
sw.Start();
Parallel.ForEach(matches, new ParallelOptions{MaxDegreeOfParallelism = 20}, m =>
{
if (cDict.TryGetValue(m, out var item))
cResults.Add(item);
});
sw.Stop();
var t = sw.ElapsedMilliseconds;
sw.Reset();
return t;
}).Average());
有什么办法可以加快速度吗是的,很多。哪一个最好,你得做些研究。查看Task.Run()
可能是一个选项,或者parrelell.ForEach
,这会“更快”吗?也许,您必须测试它。当然,如果您将这个CSV加载到SQL之类的东西中,它可以更快地处理这些数据Dictionary
可能会加快查找速度,但您必须将其与最初创建Dictionary的开销进行权衡。基本上,这太广泛了。如果您不希望有太多匹配项,那么请缓存所有证书id,对id进行搜索,如果您有matach,则进行查询以按id提取证书对象。证书中应该只有一个匹配项。AllID但是证书列表包含多个订单的结果。证书中是否存在重复项?我的意思是,具有相同ID
的项目?两个ID列表中都没有重复项。谢谢丹尼斯,字典确实帮了大忙,我现在每分钟处理数千个而不是数百个。要翻出170万条记录还需要一段时间,但至少现在要在我退休前完成。哪个列表有170万条记录?请张贴两个列表大小。证书包含1.7mil,所有订单ID包含90k到350k ID,具体取决于正在处理的订单对象。从证书列表中删除证书的附加处理是否值得花费时间,例如,当证书匹配并处理后,将其从列表中删除,因为它不会被使用或再次需要。Hmm。字典查找工作非常快。不需要从字典中删除项-它不会执行得更快。什么是输出
?设置OrderUnitID.Completed
是否只是设置一个bool
(无副作用)?我的意思是,只要遍历列表
(如果Order.AllIDs
是一个列表)和字典查找应该不会花费太多时间。抱歉,output.add只是一个示例行,实际行包含安全敏感信息。它基本上是将cert对象的一些属性和一个masterkey添加到一个字符串中,该字符串稍后将输出到csv。Order.AllIDs是IDS对象的列表,其中包含ID作为字符串和布尔值。
Master List Size: 2158882
Matches List Size: 350000
CurrentCultureIgnoreCase Elapsed Time (avg): 298.2
ToUpper() Elapsed Time (avg): 179.6
OrdinalIgnoreCase Elapsed Time (avg): 163.9
Parallel Elapsed Time (avg): 74.6