Does the order of LINQ functions matter?

基本上,正如问题所述... LINQ 函数的顺序是否与 表演有关?显然结果还是一样的。

例如:

myCollection.OrderBy(item => item.CreatedDate).Where(item => item.Code > 3);
myCollection.Where(item => item.Code > 3).OrderBy(item => item.CreatedDate);

两者都返回相同的结果,但是在不同的 LINQ 顺序中。我意识到重新排序一些项目会导致不同的结果,我并不关心这些。我主要关心的是,在获得相同的结果时,排序是否会影响性能。而且,不仅仅是在我打出的2个 LINQ 调用(OrderBy,Where)上,而是在任何 LINQ 调用上。

8795 次浏览

在您的特定示例中,可以会对性能产生影响。

第一个查询: 您的 OrderBy调用需要遍历 完整的源序列,包括那些 Code为3或更少的项。然后,Where子句还需要迭代 完整的顺序序列。

第二个查询: Where调用仅限于那些 Code大于3的项。然后,OrderBy调用只需要遍历由 Where调用返回的缩减序列。

是的。

但是确切地说,性能差异取决于 LINQ 提供程序如何计算底层表达式树。

例如,对于 LINQ-to-XML,您的查询可能第二次执行得更快(首先是 WHERE 子句) ,但对于 LINQ-to-SQL,第一次执行得更快。

为了准确地找出性能差异是什么,您很可能需要对应用程序进行概要分析。但是,像以往一样,过早的优化通常不值得付出努力——您可能会发现 LINQ 性能以外的问题更为重要。

It will depend on the LINQ provider in use. For LINQ to Objects, that could certainly make a 巨大 difference. Assume we've actually got:

var query = myCollection.OrderBy(item => item.CreatedDate)
.Where(item => item.Code > 3);


var result = query.Last();

这需要对 完整集合进行排序并筛选 那么。如果我们有一百万个项目,其中只有一个项目的代码大于3,我们将浪费大量的时间来排序将被丢弃的结果。

与反向操作相比,首先过滤:

var query = myCollection.Where(item => item.Code > 3)
.OrderBy(item => item.CreatedDate);


var result = query.Last();

This time we're only ordering the filtered results, which in the sample case of "just a single item matching the filter" will be a lot more efficient - both in time and space.

它还决定了查询是否正确执行,请考虑:

var query = myCollection.Where(item => item.Code != 0)
.OrderBy(item => 10 / item.Code);


var result = query.Last();

没关系,我们知道我们永远不会除以0。但是如果我们执行排序 之前过滤,查询将抛出异常。

It depends on the relevancy. Suppose if you have very few items with Code=3, then the next order will work on small set of collection to get the order by date.

Whereas if you have many items with the same CreatedDate, then the next order will work on larger set of collection to get the order by date.

因此,在这两种情况下,性能都会有所不同

在 Linq-To-Objects:

排序相当慢,而且使用 O(n)内存。另一方面,Where相对较快,并且使用常量内存。因此,首先执行 Where将会更快,对于大型集合来说则会更快。

减少的内存压力也很重要,因为在大对象堆上的分配(以及它们的集合)在我的经验中是相对昂贵的。

显然结果还是一样的。

请注意,这实际上并不正确——特别是,下面两行将给出不同的结果(对于大多数提供者/数据集) :

myCollection.OrderBy(o => o).Distinct();
myCollection.Distinct().OrderBy(o => o);

值得注意的是,在考虑使用 怎么做优化 LINQ 查询时应该小心。例如,如果使用 LINQ 的声明式版本执行以下操作:

public class Record
{
public string Name { get; set; }
public double Score1 { get; set; }
public double Score2 { get; set; }
}




var query = from record in Records
order by ((record.Score1 + record.Score2) / 2) descending
select new
{
Name = record.Name,
Average = ((record.Score1 + record.Score2) / 2)
};

如果,不管出于什么原因,您决定通过将平均值先存储到一个变量中来“优化”查询,那么您不会得到所需的结果:

// The following two queries actually takes up more space and are slower
var query = from record in Records
let average = ((record.Score1 + record.Score2) / 2)
order by average descending
select new
{
Name = record.Name,
Average = average
};


var query = from record in Records
let average = ((record.Score1 + record.Score2) / 2)
select new
{
Name = record.Name,
Average = average
}
order by average descending;

我知道没有多少人使用声明性 LINQ 对象,但它是一些好的食物思考。