此LINQ代码是否对原始数据执行多次查找?

Mar*_*tin 9 c# linq linq-to-objects

我们在使用LINQ的代码段中遇到了轻微的性能问题,并且提出了一个关于LINQ如何在查找方面工作的问题

我的问题是这个(请注意我已经更改了所有代码,因此这是代码的指示性示例,而不是真实场景):

特定

public class Person {
 int ID;
 string Name;
 DateTime Birthday; 
 int OrganisationID;
}
Run Code Online (Sandbox Code Playgroud)

如果我有一个说100k Person对象的列表,然后是一个日期列表,比如1000,我运行了这段代码:

var personBirthdays = from Person p in personList
    where p.OrganisationID = 123
    select p.Birthday;

foreach (DateTime d in dateList)
{
    if (personBirthdays.Contains(d))
        Console.WriteLine(string.Format("Date: {0} has a Birthday", d.ToShortDateString()));
}
Run Code Online (Sandbox Code Playgroud)

结果代码将是以下迭代:

100k(用于查找具有organisationID 123的用户需要完成的循环)
乘以
1000(列表中的日期数量)
乘以
x(具有要检查的组织ID 123的用户数量的日期) )

这是很多迭代!

如果我将personBirthdays的代码更改为:

List<DateTime> personBirthdays = 
        (from Person p in personList
        where p.OrganisationID = 123
        select p.Birthday).ToList();
Run Code Online (Sandbox Code Playgroud)

这应该删除100k作为倍数,并只执行一次?

所以你会有100k +(1000*x)而不是(100k*1000*x).

问题是,这似乎太容易了,我确信LINQ在某个地方做了一些聪明的事情应该意味着这不会发生.

如果没有人回答,我会进行一些测试并报告.

清晰度更新: 我们不考虑数据库查找,该personList对象是内存列表对象.这就是所有LINQ到对象.

Ser*_*rvy 8

这应该删除10k作为倍数,并只执行一次?

这意味着,不是迭代personList100k次,而是为每个迭代执行whereselect操作,你将迭代100k次,并且只对底层数据源执行一次和操作.Listwhereselect

问题是,这似乎太容易了,我确信LINQ在某个地方做了一些聪明的事情应该意味着这不会发生.

不,你的第一个查询只是你不应该使用LINQ做的事情,你应该采取查询的结果并将它们放入数据结构,如果你打算多次迭代它们(这是你改变的) .

您可以使用适当的数据结构进一步改进此查询.搜索a List是相当低效的,因为它需要进行线性搜索.最好使用a HashSet来存储查询的结果.A HashSet在平均情况下具有O(1)搜索速度,而不是a的O(n)搜索时间List.

var dates = new HashSet<DateTime>(from Person p in personList
                                  where p.OrganisationID = 123
                                  select p.Birthday);

foreach (DateTime d in dateList.Where(date => dates.Contains(date)))
{
    Console.WriteLine(string.Format("Date: {0} has a Birthday", d.ToShortDateString()));
}
Run Code Online (Sandbox Code Playgroud)