적절한 Linq where 절


133

나는 일상 생활에서 상당한 양의 linq를 작성하지만 대부분 간단한 진술을합니다. where 절을 사용할 때 여러 가지 방법으로 작성할 수 있으며 각각 내가 알 수있는 한 동일한 결과를 얻습니다. 예를 들어;

from x in Collection
  where x.Age == 10
  where x.Name == "Fido"
  where x.Fat == true
  select x;

결과와 관련하여 최소한 이것과 동등한 것으로 보입니다.

from x in Collection
  where x.Age == 10 &&
        x.Name == "Fido" &&
        x.Fat == true
  select x;

구문과 다른 점이 실제로 있습니까? 그렇다면 선호하는 스타일은 무엇이며 왜 그렇습니까?


203
부울 Fat속성이 있습니까? 그것은 명백한 의미입니다.
Bala R

104
@ 발라 R : 이봐, 개가 뚱뚱하면 개는 뚱뚱해.
AR

답변:


76

두 번째 것은 컬렉션의 각 항목에 대해 평가 할 술어가 하나 있기 때문에보다 효율적입니다. 첫 번째 항목에서와 같이 첫 번째 술어를 모든 항목에 먼저 적용하고 결과 (이 시점에서 좁혀 짐)는 다음과 같습니다. 두 번째 술어 등에 사용됩니다. 패스마다 결과가 좁아 지지만 여전히 여러 패스가 필요합니다.

또한 연결 (첫 번째 방법)은 술어를 AND 처리하는 경우에만 작동합니다. 이와 같은 것은 x.Age == 10 || x.Fat == true첫 번째 방법으로는 작동하지 않습니다.


1
이 확장을 사용하면 체인 ORing 조건이 다소 가능합니다 : albahari.com/nutshell/predicatebuilder.aspx
jahu

142

편집 : LINQ to Objects는 내가 기대했던대로 작동하지 않습니다. 내가 방금 작성한 블로그 게시물에 관심이있을 수 있습니다 ...


그것들은 소위 무엇이 될지에 따라 다릅니다-첫 번째는 다음과 같습니다.

Collection.Where(x => x.Age == 10)
          .Where(x => x.Name == "Fido")
          .Where(x => x.Fat == true)

후자는 다음과 같습니다.

Collection.Where(x => x.Age == 10 && 
                      x.Name == "Fido" &&
                      x.Fat == true)

실제로 실제로 어떤 차이점이 구현에 따라 달라집니다Where 지는 호출되는 있습니다. 그것이 SQL 기반 공급자라면 두 사람이 같은 SQL을 만들 것으로 기대합니다. 그것이 LINQ to Objects에 있다면, 두 번째는 더 적은 간접 레벨을 가질 것입니다 (4 개 대신 2 개의 반복자가있을 것입니다). 속도 측면에서 이러한 간접 수준이 중요한지 여부 는 다른 문제입니다.

일반적으로 여러 where절이 상당히 다른 조건을 나타내는 것처럼 느껴질 경우 (예 : 하나는 객체의 한 부분과 관련이 있고 하나는 완전히 별 개임) where여러 절을 사용하고 다양한 조건이 밀접하게 관련되어있는 경우 (예 : 특정 값) 최소값보다 크고 최대 값보다 작음). 기본적으로 약간의 성능 차이 전에 가독성을 고려할 가치가 있습니다.


1
@JonSkeet 어쩌면 틀렸을 지 모르지만 Linq의 빠른 검토 후 구현은 확실하지 않습니다. 중첩 된 위치는 정적 메소드 'CombinePredicates'에 의해 결합됩니다. 술어가 결합 된 단일 반복자에 의해 콜렉션이 한 번만 반복됩니다. 물론 func를 결합하면 성능에 영향을 주지만 매우 제한적입니다. 괜찮 으세요?
Cybermaxs

@ Cybermaxs : 정확히 무엇인지 확실하지 않습니까? 컬렉션이 두 번 이상 반복 될 것을 제안한 적이 없습니다.
Jon Skeet

물론 @JonSkeet 그러나 모든 술어가 결합되고 하나의 반복자 만 관련됩니다. Enumerable.WhereSelectEnumerableIterator를보십시오.
Cybermaxs

연결 한 페이지가 다운되었습니다. 기사가 여전히 다른 곳에 있다면 링크를 업데이트 해 주시겠습니까? 감사.
Asad Saeeduddin

2
@Asad : 업데이트되었습니다. (내 블로그가 이동했습니다.)
Jon Skeet

13

첫 번째가 구현됩니다.

Collection.Where(x => x.Age == 10)
          .Where(x => x.Name == "Fido") // applied to the result of the previous
          .Where(x => x.Fat == true)    // applied to the result of the previous

훨씬 더 간단하고 ( 아마도 더 빠를 것임) 반대로 :

// all in one fell swoop
Collection.Where(x => x.Age == 10 && x.Name == "Fido" && x.Fat == true)

6
"빠르게"? 우리는 아직 어떤 LINQ 구현이 포함되어 있는지 알지 못하므로 성능에 영향을 미치기가 어렵습니다.
Jon Skeet 2016 년

일반적인 경우 후자는 1 루프 만 필요합니다. 공급자는 첫 번째 예를 병합하도록 선택할 수 있지만 필수는 아닙니다.
user7116 2016 년

2
실제로 ...하지만 후자 훨씬 빠르다고 주장합니다 . 그것이 훨씬 더 빠를 것이라는 것은 분명하지 않습니다. 결국 성능 차이의 중요성은 이것이 어떻게 사용되는지에 달려 있습니다.
Jon Skeet 2016 년

1
@Jon : 의견이 맞지 않습니다. 참고로 LINQ 공급자는 실제 표현에 유용한 최적화 변환을 수행 할 수 있습니다. 그러나 두 번째 루프는 단 하나의 루프 만 필요하고 부울 단락으로 인한 이점을 감안할 때 일반적인 용어로 왜 "더 빠르다"로 표시되어서는 안되는지 알기가 어렵습니다. OP에 5 개의 요소 만 있으면 내 요점이 무의미합니다.
user7116

11

내가 달릴 때

from c in Customers
where c.CustomerID == 1
where c.CustomerID == 2
where c.CustomerID == 3
select c

from c in Customers
where c.CustomerID == 1 &&
c.CustomerID == 2 &&
c.CustomerID == 3
select c customer table in linqpad

내 고객 테이블에 대해 동일한 SQL 쿼리가 출력됩니다.

-- Region Parameters
DECLARE @p0 Int = 1
DECLARE @p1 Int = 2
DECLARE @p2 Int = 3
-- EndRegion
SELECT [t0].[CustomerID], [t0].[CustomerName]
FROM [Customers] AS [t0]
WHERE ([t0].[CustomerID] = @p0) AND ([t0].[CustomerID] = @p1) AND ([t0].[CustomerID] = @p2)

따라서 sql 로의 번역에는 차이가 없으며 다른 답변에서 람다 식으로 변환되는 방법을 이미 보았습니다.


좋아, 그런 다음이 중 하나를 사용하면 성능에 영향을 미치지 않는다고 말하고 싶습니까?
Bimal Das

WHERE 절은 실제로 연결되어 있습니다. 따라서 어떻게 쓰는지는 중요하지 않습니다. 성능 차이는 없습니다.
hastrb

3

후드를 살펴보면 두 명령문이 다른 쿼리 표현으로 변환됩니다. 에 따라 QueryProviderCollection 이 멀리 최적화 여부 될 수 있습니다.

이것이 linq-to-object 호출 인 경우 여러 where 절은 서로 읽은 IEnumerable 체인으로 이어집니다. 단일 조항 양식을 사용하면 성능이 향상됩니다.

기본 공급자가 SQL 문으로 변환하면 두 변형이 모두 같은 문을 만들 가능성이 높습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.