答案取决于您的集合状态。
- 如果大多数实体通过Where测试,请先应用Select;
- 如果较少的实体通过Where测试,请先应用Where。
更新:
@YeldarKurmangaliyev 给出了具体的示例和基准测试的答案。我运行了类似的代码来验证他的说法,我们的结果完全相反,因为我使用的测试对象不像他用于运行测试的简单的Point
类型那么简单。
这段代码看起来非常像他的代码,只是我将类名从Point
更改为EnumerableClass
。
以下是我用于构成EnumerableClass
类的类:
public class EnumerableClass
{
public int X { get; set; }
public int Y { get; set; }
public String A { get; set; }
public String B { get; set; }
public String C { get; set; }
public String D { get; set; }
public String E { get; set; }
public Frame F { get; set; }
public Gatorade Gatorade { get; set; }
public Home Home { get; set; }
}
public class Home
{
private Home(int rooms, double bathrooms, Stove stove, InternetConnection internetConnection)
{
Rooms = rooms;
Bathrooms = (decimal) bathrooms;
StoveType = stove;
Internet = internetConnection;
}
public int Rooms { get; set; }
public decimal Bathrooms { get; set; }
public Stove StoveType { get; set; }
public InternetConnection Internet { get; set; }
public static Home GetUnitOfHome()
{
return new Home(5, 2.5, Stove.Gas, InternetConnection.Att);
}
}
public enum InternetConnection
{
Comcast = 0,
Verizon = 1,
Att = 2,
Google = 3
}
public enum Stove
{
Gas = 0,
Electric = 1,
Induction = 2
}
public class Gatorade
{
private Gatorade(int volume, Color liquidColor, int bottleSize)
{
Volume = volume;
LiquidColor = liquidColor;
BottleSize = bottleSize;
}
public int Volume { get; set; }
public Color LiquidColor { get; set; }
public int BottleSize { get; set; }
public static Gatorade GetGatoradeBottle()
{
return new Gatorade(100, Color.Orange, 150);
}
}
public class Frame
{
public int X { get; set; }
public int Y { get; set; }
private Frame(int x, int y)
{
X = x;
Y = y;
}
public static Frame GetFrame()
{
return new Frame(5, 10);
}
}
类Frame
、Gatorade
和Home
都有一个静态方法,用于返回它们类型的实例。
以下是主程序:
public static class Program
{
const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static readonly Random Random = new Random();
private static string RandomString(int length)
{
return new string(Enumerable.Repeat(Chars, length)
.Select(s => s[Random.Next(s.Length)]).ToArray());
}
private static void Main()
{
var random = new Random();
var largeCollection =
Enumerable.Range(0, 1000000)
.Select(
x =>
new EnumerableClass
{
A = RandomString(500),
B = RandomString(1000),
C = RandomString(100),
D = RandomString(256),
E = RandomString(1024),
F = Frame.GetFrame(),
Gatorade = Gatorade.GetGatoradeBottle(),
Home = Home.GetUnitOfHome(),
X = random.Next(1000),
Y = random.Next(1000)
})
.ToList();
const int conditionValue = 250;
Console.WriteLine(@"Condition value: {0}", conditionValue);
var sw = new Stopwatch();
sw.Start();
var firstWhere = largeCollection
.Where(x => x.Y < conditionValue)
.Select(x => x.Y)
.ToArray();
sw.Stop();
Console.WriteLine(@"Where -> Select: {0} ms", sw.ElapsedMilliseconds);
sw.Restart();
var firstSelect = largeCollection
.Select(x => x.Y)
.Where(y => y < conditionValue)
.ToArray();
sw.Stop();
Console.WriteLine(@"Select -> Where: {0} ms", sw.ElapsedMilliseconds);
Console.ReadLine();
Console.WriteLine();
Console.WriteLine(@"First Where's first item: {0}", firstWhere.FirstOrDefault());
Console.WriteLine(@"First Select's first item: {0}", firstSelect.FirstOrDefault());
Console.WriteLine();
Console.ReadLine();
}
}
结果:
我运行了多次测试并发现,在集合大小为1000000时,
.Select().Where() 比 .Where().Select().
表现更好。
以下是需要翻译的内容:
这是第一个测试结果,我强制将每个EnumerableClass
对象的Y
值设置为5,因此每个项目都通过了Where:
Condition value: 250
Where -> Select: 149 ms
Select -> Where: 115 ms
First Where's first item: 5
First Select's first item: 5
以下是第二个测试结果,我强制每个
EnumerableClass
对象的
Y
值为251,因此没有任何项目通过了
Where:
Condition value: 250
Where -> Select: 110 ms
Select -> Where: 100 ms
First Where's first item: 0
First Select's first item: 0
显然,结果非常依赖于集合的状态:
- 在@YeldarKurmangaliyev的测试中,.Where().Select()表现更好; 和,
- 在我的测试中,.Select().Where()表现更好。
我一遍又一遍地提到的集合的状态包括:
- 每个项目的大小;
- 集合中的总项目数; 和,
- 可能通过Where子句的项目数。
回应评论:
此外,@Enigmativity说,在知道Where的结果以便确定先放置Where还是先放置之前,这是一个进退两难的局面。理论上,他是正确的,而且不出所料,在计算机科学的另一个领域Scheduling中也存在这种情况。
最佳调度算法是最短作业优先,我们首先安排执行时间最短的作业。但是,有人怎么知道一个特定作业需要多长时间才能完成呢?嗯,答案是:
在准确估计运行时间的专门环境中使用最短作业优先。
因此,正如我在一开始时所说的(这也是我的回答的第一个、较短版本),这个问题的正确答案将取决于集合的当前状态。
一般来说,
- 如果您的对象在合理的大小范围内; 并且,
- 您正在从每个对象中选择一个非常小的块; 并且,
- 您的集合大小也不仅仅是几千个,
那么本答案开头提到的指导方针将对您有用。
Where
根据条件返回的记录比Select
返回的记录少。而Select
首先返回所有记录,然后对其进行条件过滤。因此,使用Where
应该会提高性能。不过,你可以尝试在一个包含 10000 条以上记录的巨大测试数据库中测试你的查询。好问题! - Keyur PATEL