Означает ли порядок функций LINQ?
В принципе, поскольку в вопросе говорится, что порядок функций LINQ имеет значение performance? Очевидно, что результаты должны быть идентичны еще...
Пример:
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.
Ответы
Ответ 1
Это будет зависеть от используемого поставщика 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. Но если мы выполним упорядочение перед фильтрацией, запрос будет генерировать исключение.
Ответ 2
Да.
Но именно то, что эта разница в производительности зависит от того, как базовое дерево выражений оценивается поставщиком LINQ.
Например, ваш запрос может выполняться быстрее во второй раз (сначала с предложением WHERE) для LINQ-to-XML, но быстрее в первый раз для LINQ-to-SQL.
Чтобы точно определить разницу в производительности, вы, скорее всего, захотите профилировать свое приложение. Как всегда с такими вещами, преждевременная оптимизация обычно не стоит усилий - вы можете найти проблемы, отличные от производительности LINQ, более важные.
Ответ 3
В вашем конкретном примере это может повлиять на производительность.
Первый запрос: вашему вызову OrderBy
необходимо выполнить итерацию по всей исходной последовательности, включая те элементы, где Code
равно 3 или меньше. В предложении Where
также необходимо выполнить итерацию всей упорядоченной последовательности.
Второй запрос: вызов Where
ограничивает последовательность только теми элементами, где Code
больше 3. Для вызова OrderBy
требуется только пройти приведенную последовательность, возвращаемую вызовом Where
.
Ответ 4
В Linq-To-Objects:
Сортировка выполняется довольно медленно и использует память O(n)
. Where
, с другой стороны, относительно быстро и использует постоянную память. Поэтому выполнение Where
сначала будет быстрее, а для больших коллекций значительно быстрее.
Уменьшенное давление памяти также может быть значительным, так как распределение на кучу большого объекта (вместе с их сборкой) относительно дорогое по моему опыту.
Ответ 5
Очевидно, что результаты должны быть одинаковыми...
Обратите внимание, что это на самом деле не так: в частности, следующие две строки будут давать разные результаты (для большинства поставщиков/наборов данных):
myCollection.OrderBy(o => o).Distinct();
myCollection.Distinct().OrderBy(o => o);
Ответ 6
Стоит отметить, что вы должны быть осторожны при рассмотрении how для оптимизации запроса 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 для объектов, но это хорошая идея для размышлений.
Ответ 7
Это зависит от релевантности. Предположим, если у вас очень мало элементов с кодом = 3, то следующий порядок будет работать с небольшим набором коллекций, чтобы получить заказ по дате.
Если у вас есть много элементов с тем же созданным, то следующий порядок будет работать с большим набором коллекций, чтобы получить порядок по дате.
Итак, в обоих случаях будет разница в производительности