LINQ函数的顺序是否重要?

时间:2011-09-21 12:01:26

标签: c# performance linq

基本上,正如问题所述...... 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调用上。

7 个答案:

答案 0 :(得分:143)

这取决于使用的LINQ提供程序。对于LINQ to Objects,这肯定会产生巨大的差异。假设我们实际上得到了:

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();

这次我们只是对过滤后的结果进行排序,在“只有一个与过滤器匹配的项目”的示例中,它将在时间和空间上更加高效。

考虑:

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

var result = query.Last();

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

答案 1 :(得分:17)

的性能差异究竟取决于LINQ提供程序如何评估基础表达式树。

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

要准确了解性能差异,您很可能想要分析您的应用程序。尽管如此,过早优化通常不值得努力 - 您可能会发现LINQ性能以外的问题更为重要。

答案 2 :(得分:5)

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

首次查询:您的OrderBy调用需要遍历整个源序列,包括Code为3或更少的项目。然后Where子句还需要迭代整个有序序列。

第二个查询:Where调用仅将序列限制为Code大于3的项。OrderBy调用只需要遍历{返回的减少的序列{1}}致电。

答案 3 :(得分:3)

在Linq-To-Objects中:

排序相当慢并使用O(n)内存。另一方面,Where相对较快并且使用恒定的内存。因此,首先执行Where会更快,而对于大型集合则要快得多。

内存压力降低也很大,因为根据我的经验,大对象堆上的分配(连同它们的集合)相对昂贵。

答案 4 :(得分:1)

  

显然结果必须相同......

请注意,实际上并非如此 - 特别是,以下两行将给出不同的结果(对于大多数提供者/数据集):

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

答案 5 :(得分:1)

值得注意的是,在考虑如何优化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作为对象,但它是一些值得思考的好东西。

答案 6 :(得分:0)

这取决于相关性。假设您的Code = 3的项目非常少,那么下一个订单将适用于小型集合,以便按日期获取订单。

如果您有许多具有相同CreatedDate的项目,那么下一个订单将适用于更大的集合集合以按日期获取订单。

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