Имеет ли значение порядок функций LINQ? - PullRequest
112 голосов
/ 21 сентября 2011

В основном, как говорится в вопросе ... имеет ли значение порядок функций 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 ]

144 голосов
/ 21 сентября 2011

Это будет зависеть от используемого поставщика 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. Но если мы выполним порядок до фильтрации, запрос выдаст исключение.

17 голосов
/ 21 сентября 2011

Да.

Но в точности какая разница в производительности зависит от того, как базовое дерево выражений оценивается поставщиком LINQ.

Например, ваш запрос может выполняться быстрее во второй раз (сначала с предложением WHERE) для LINQ-to-XML, но быстрее в первый раз для LINQ-to-SQL.

Чтобы точно определить разницу в производительности, вы, скорее всего, захотите профилировать свое приложение. Однако, как и в случае с такими вещами, преждевременная оптимизация, как правило, не стоит затраченных усилий - вы, возможно, сочтете, что проблемы, помимо производительности LINQ, более важны.

5 голосов
/ 21 сентября 2011

В вашем конкретном примере это может повлиять на производительность.

Первый запрос: ваш OrderBy вызов должен выполнить итерацию всей исходной последовательности вся включая те, у которых Code равно 3 или меньше.Тогда в предложении Where также необходимо выполнить итерацию упорядоченной последовательности вся .

Второй запрос: вызов Where ограничивает последовательность только теми элементами, у которых Code больше 3В этом случае вызову OrderBy требуется только пересмотреть сокращенную последовательность, возвращаемую вызовом Where.

3 голосов
/ 21 сентября 2011

В Linq-To-Objects:

Сортировка выполняется довольно медленно и использует O(n) памяти.Where, с другой стороны, относительно быстр и использует постоянную память.Таким образом, выполнение Where сначала будет быстрее, а для больших коллекций - значительно быстрее.

Снижение нагрузки на память также может быть значительным, поскольку выделения в куче больших объектов (вместе с их коллекцией) относительно дороги в моемопыт.

1 голос
/ 23 октября 2012

Стоит отметить, что вы должны быть осторожны при рассмотрении как оптимизировать запрос 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 для объектов, но это хорошая пища для размышлений.

1 голос
/ 21 сентября 2011

Очевидно, что результаты должны быть идентичны ...

Обратите внимание, что на самом деле это не так - в частности, следующие две строки дадут разные результаты (для большинства поставщиков / наборов данных):

myCollection.OrderBy(o => o).Distinct();
myCollection.Distinct().OrderBy(o => o);
0 голосов
/ 21 сентября 2011

Зависит от актуальности. Предположим, что если у вас очень мало товаров с кодом = 3, то следующий заказ будет работать с небольшим набором коллекции, чтобы получить заказ по дате.

Принимая во внимание, что если у вас много элементов с одинаковой CreatedDate, то следующий заказ будет работать с большим набором коллекций, чтобы получить заказ по дате.

Итак, в обоих случаях будет разница в производительности

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...