[c#] 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 호출에서도 마찬가지입니다.



답변

사용중인 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으로 나누지 않을 것임을 알고 있습니다. 그러나 필터링 전에 순서를 지정 하면 쿼리에서 예외가 발생합니다.


답변

예.

그러나 성능 차이가 정확히 무엇인지 는 LINQ 공급자가 기본 식 트리를 평가하는 방법에 따라 다릅니다.

예를 들어 쿼리는 LINQ-to-XML의 경우 두 번째 (WHERE 절을 먼저 사용) 더 빠르게 실행되지만 LINQ-to-SQL의 경우 처음에는 더 빠르게 실행될 수 있습니다.

성능 차이가 무엇인지 정확히 알아 보려면 애플리케이션을 프로파일 링해야 할 것입니다. 하지만 그런 것과 마찬가지로 조기 최적화는 일반적으로 노력할 가치가 없습니다. LINQ 성능 이외의 문제가 더 중요하다는 것을 알 수 있습니다.


답변

특정 예 에서는 성능에 차이를 만들 수 있습니다 .

첫 번째 쿼리 : OrderBy호출 이 3 이하인 항목을 포함 하여 전체 소스 시퀀스 를 반복해야합니다 Code. Where절은 또한 반복 할 필요가 전체가 순서를 명령했다.

두 번째 쿼리 : Where호출 Code은 3보다 큰 항목으로 만 시퀀스를 제한합니다 . 그러면 호출에서 OrderBy반환 된 축소 시퀀스 만 통과하면됩니다 Where.


답변

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를 사용하는 것은 아니지만 생각하기에 좋은 음식입니다.


답변

관련성에 따라 다릅니다. 코드 = 3 인 항목이 매우 적다고 가정하면 다음 주문은 작은 컬렉션 집합에서 작동하여 날짜별로 주문을받습니다.

동일한 CreatedDate를 가진 항목이 많은 경우 다음 주문은 더 큰 컬렉션 집합에서 작동하여 날짜별로 주문을 가져옵니다.

따라서 두 경우 모두 성능에 차이가 있습니다.