C# 比较大型数据集时使用嵌套循环时速度较慢
我正在使用LINQtoEntities检索两个数据集列表。它们都在同一个数据库中,但我需要将一个表转换为任务表,因为它已集成到我的日历中。我敢肯定,这里不值得详细讨论,但我希望加快匹配id和创建新任务对象的过程。这是一个一劳永逸的代码片段,所以即使速度很慢,我也可以让程序在一夜之间运行。然而,为了将来的参考,我想要一些关于提高效率的建议C# 比较大型数据集时使用嵌套循环时速度较慢,c#,linq,entity-framework,C#,Linq,Entity Framework,我正在使用LINQtoEntities检索两个数据集列表。它们都在同一个数据库中,但我需要将一个表转换为任务表,因为它已集成到我的日历中。我敢肯定,这里不值得详细讨论,但我希望加快匹配id和创建新任务对象的过程。这是一个一劳永逸的代码片段,所以即使速度很慢,我也可以让程序在一夜之间运行。然而,为了将来的参考,我想要一些关于提高效率的建议 var accounts = data.Accounts.ToList().OrderBy(a => a.ID); Incidents[] Inciden
var accounts = data.Accounts.ToList().OrderBy(a => a.ID);
Incidents[] Incidents = data.Incidents.ToArray();
for (int i=0;i<Incidents.Length;i++)
{
foreach (var a in accounts)
{
if (a.Acct_CID == Incidents[i].CustomerID)
{
Tasks t = new Tasks();
t.creator_id = a.ID;
t.start_date = Incidents[i].DateOpened;
t.end_date = Incidents[i].DateCLosed;
t.product_code = Incidents[i].ProductCode;
t.install_type = Incidents[i].InstallType;
t.os = Incidents[i].OSType;
t.details = Incidents[i].Description;
t.solution = Incidents[i].Solution;
t.creator_name = Incidents[i].TechID;
t.category = Incidents[i].Title;
t.text = "Ticket for" + " " + Incidents[i].Name;
if (t.end_date == DateTime.MinValue || t.end_date == null)
t.status_id = 6;
else t.status_id = 7;
data.Tasks.Add(t);
break;
}
}
}
data.SaveChanges();
var accounts=data.accounts.ToList().OrderBy(a=>a.ID);
事件[]事件=data.incents.ToArray();
对于(int i=0;i替换该行
var accounts = data.Accounts.ToList().OrderBy(a => a.ID);
用这个
var accounts = data.Accounts.OrderBy(a => a.ID).ToList();
这将让数据库进行排序,然后缓存排序的结果。您现在拥有的内容会将所有内容都拉入,然后在每次到达foreach
循环时对它们进行排序(accounts
再次被枚举)
我不能说它会有很大的改进,但是如果您的数据集足够大,多次重新排序一个大的列表肯定会减慢您的速度
第二眼,每次你不只是排序<代码>帐号,但是你似乎只寻找记录的一小部分,但是你正在对整个数组进行迭代。考虑替换< /P>
foreach (var a in accounts)
{
if (a.Acct_CID == Incidents[i].CustomerID)
{
与
为什么不连接表并动态创建任务
var tasks = from i in data.Incidents
join a in data.Accounts on i.CustomerID equals a.Acct_CID
select new Tasks()
{
creator_id = a.ID,
start_date = i.DateOpened,
end_date = i.DateCLosed
// ...
};
顺便说一句,我不认为排序在这里有意义,所以无论您以何种顺序将创建的任务添加到数据库中都不重要
// Query will not be executed until here
foreach(var task in tasks)
data.Tasks.Add(task);
data.SaveChanges();
我将加入
数据库中的结果
var joinedResult = data.Accounts.Join(data.Incidents,
a => a.Acct_CID,
i => i.CustomerID,
(a, i) => new { Account = a, Incident = i });
foreach (var item in joinedResult)
{
Tasks t = new Tasks();
t.creator_id = item.Account.ID;
t.start_date = item.Incident.DateOpened;
........
}
创建帐户的查找
var accountsLookup = data.Accounts.ToLookup(a => a.Acct_CID);
foreach (var incident in data.Incidents)
{
foreach (var a in accountsLookup[incident.CustomerID])
{
Tasks t = new Tasks();
t.creator_id = a.ID;
...
}
}
data.SaveChanges();
如果帐户是唯一的,您还可以创建一个字典
var accountsDict = data.Accounts.ToDictionary(a => a.Acct_CID);
foreach (var incident in data.Incidents)
{
Account a;
if (accountsDict.TryGetValue(incident.CustomerID, out a)
{
Tasks t = new Tasks();
t.creator_id = a.ID;
...
}
}
data.SaveChanges();
这将比第一个变体快。请注意,字典的查找时间是恒定的,不取决于它的大小。因此,循环的执行时间基本上是O(n)。原始实现的执行时间是O(n^2)执行时间。抱歉,这是一个代码中没有显示的单独方法的排序,这是一个巨大的项目。我很惊讶我没有想到这一点。今天运行coffeeless,感谢您的帮助sirI,我很惊讶我也没有想到它。@Chazt3n欢迎:)顺便说一句,尽可能晚地调用ToList()、ToArray()和其他To*操作。所有这些都会强制执行查询,后续处理只会在内存中进行。不能在LINQ to Entities查询中构造实体或复杂类型“TRX.CRM.Dashboard.Web.UI.Models.Tasks”。@Chazt3n您可以返回匿名对象并映射到您的任务实体。如果可以,我会标记您的两个答案都是正确的,这确实是一个错误掷硬币,我给了你们一个+1,谢谢你们的帮助,你们真是太棒了。在这个例子中,它似乎没有迭代过任何东西?我只是无法看到这个迭代,还是它实际上不认为有一个列表?超时已过期。操作完成前已过超时时间,或者服务器没有响应。我得到了这个错误,我可以通过调用data.Accounts和data.incents上的tolist()来修复它,但它甚至比嵌套循环还要慢。@Chazt3n-它不仅仅是OrderBy。其中,选择,分组等。。。每次枚举IEnumerable时(例如每次启动新的foreach
),返回IEnumerable的所有内容都将重新求值。在使用数据之前,最好始终将ToList()
、ToDictionary()
等作为最后一件事。这就是最终解决问题的原因,感谢您的帮助和时间,但是我必须开始一个新问题来解决问题。为什么您不接受我的答案,如果您使用我的查询并按照我所说的操作,您可以返回匿名对象并将其映射到您的任务实体
?因为我很清楚我不知道如何使用Linq to entities实现这一点,我希望您在一瞬间感觉不好。您做得很好:)顺便说一句,完全改变您的问题并不好,因为其他人会阅读答案,他们不会理解发生了什么。最好开始新问题,或者在原始问题下写更新。因此,我将版本回滚到昨天的版本,并为您的程序提供了另一个技巧—查看一下它将执行从TasksDTO到幕后任务的映射。
var tasks = (from i in data.Incidents
join a in data.Accounts on i.CustomerID equals a.Acct_CID
select new
{
creator_id = a.ID,
start_date = i.DateOpened,
end_date = i.DateCLosed,
product_code = i.ProductCode,
install_type = i.InstallType,
os = i.OSType,
details = i.Description,
solution = i.Solution,
creator_name = i.TechID,
category = i.Title,
text = "Ticket for" + " " + i.Name,
status_id = 7
}).AsEnumerable().Select(x => new
{
x.creator_id,
x.start_date,
x.end_date,
x.product_code,
x.os,
x.details,
x.solution,
x.creator_name,
x.category,
x.text,
x.install_type,
x.status_id
});
foreach (var item in tasks)
{
Tasks t = new Tasks();
t.os = item.os;
t.id = item.creator_id;
t.install_type = item.install_type;
t.start_date = item.start_date;
t.end_date = item.end_date;
t.solution = item.solution;
t.details = item.details;
t.creator_name = item.creator_name;
t.category = item.category;
t.text = item.text;
t.product_code = item.product_code;
if (t.end_date == DateTime.MinValue || t.end_date == null)
t.status_id = 6;
else t.status_id = 7;
data.Tasks.Add(t);
}
data.SaveChanges();
var tasks = (from i in data.Incidents
join a in data.Accounts on i.CustomerID equals a.Acct_CID
select new
{
creator_id = a.ID,
start_date = i.DateOpened,
end_date = i.DateCLosed,
product_code = i.ProductCode,
install_type = i.InstallType,
os = i.OSType,
details = i.Description,
solution = i.Solution,
creator_name = i.TechID,
category = i.Title,
text = "Ticket for" + " " + i.Name,
status_id = 7
}).AsEnumerable().Select(x => new
{
x.creator_id,
x.start_date,
x.end_date,
x.product_code,
x.os,
x.details,
x.solution,
x.creator_name,
x.category,
x.text,
x.install_type,
x.status_id
});
foreach (var item in tasks)
{
Tasks t = new Tasks();
t.os = item.os;
t.id = item.creator_id;
t.install_type = item.install_type;
t.start_date = item.start_date;
t.end_date = item.end_date;
t.solution = item.solution;
t.details = item.details;
t.creator_name = item.creator_name;
t.category = item.category;
t.text = item.text;
t.product_code = item.product_code;
if (t.end_date == DateTime.MinValue || t.end_date == null)
t.status_id = 6;
else t.status_id = 7;
data.Tasks.Add(t);
}
data.SaveChanges();