IEnumerable <T> 대 IQueryable <T> 반환


1084

귀국 IQueryable<T>과 귀국의 차이점은 무엇입니까 IEnumerable<T>?

IQueryable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;

IEnumerable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;

답변:


1778

예, 둘 다 실행 연기 를 제공합니다 .

차이점은 IQueryable<T>LINQ-to-SQL (LINQ.-to-anything)이 작동하도록하는 인터페이스입니다. 따라서에 대한 쿼리를 더 세분화 IQueryable<T>하면 가능한 경우 해당 쿼리가 데이터베이스에서 실행됩니다.

IEnumerable<T>경우 LINQ-to-Object가되므로 원래 쿼리와 일치하는 모든 개체를 데이터베이스에서 메모리로로드해야합니다.

코드에서 :

IQueryable<Customer> custs = ...;
// Later on...
var goldCustomers = custs.Where(c => c.IsGold);

이 코드는 SQL을 실행하여 골드 고객 만 선택합니다. 반면 다음 코드는 데이터베이스에서 원래 쿼리를 실행 한 다음 메모리에서 비 골드 고객을 필터링합니다.

IEnumerable<Customer> custs = ...;
// Later on...
var goldCustomers = custs.Where(c => c.IsGold);

이것은 매우 중요한 차이점이며, 작업을 IQueryable<T>하면 데이터베이스에서 너무 많은 행을 리턴하지 않아도됩니다. 또 다른 주요 예는 페이징을 수행하는 것입니다. Takeand Skipon 을 사용 IQueryable하면 요청 된 행 수만 가져옵니다. 이 작업을 수행 IEnumerable<T>하면 모든 행이 메모리에로드됩니다.


32
좋은 설명입니다. IEnumerable이 IQueryable보다 선호되는 상황이 있습니까?
fjxx

8
따라서 IQueryable을 사용하여 Memory Object를 쿼리하는 경우 IEnumerable과 IQueryable 사이에 차이가 없습니까?
Tarik

11
경고 : IQueryable은 명시된 최적화로 인해 유혹적인 솔루션 일 수 있지만 리포지토리 또는 서비스 계층을 지나서는 안됩니다. 이는 "LINQ 식 누적"으로 인한 오버 헤드로부터 데이터베이스를 보호하기위한 것입니다.
Yorro

48
@fjxx 예. 원래 결과에 대해 필터링을 반복하려는 경우 (몇 가지 최종 결과). IQueryable 인터페이스에서이를 수행하면 데이터베이스에 여러 번 왕복 할 수 있습니다. IEnumerable에서 수행하는 것처럼 메모리에서 필터링을 수행하면 데이터 양이
크지

34
선호하는 또 다른 이유 IEnumerable로는 IQueryable모든 LINQ 작업이 모든 LINQ 공급자에서 지원하는 것입니다. 따라서 수행중인 작업을 알고있는 IQueryable한 많은 쿼리를 LINQ 공급자 (LINQ2SQL, EF, NHibernate, MongoDB 등)에 푸시하는 데 사용할 수 있습니다 . 그러나 다른 코드를 사용하여 원하는 작업을 수행 IQueryable하면 일부 클라이언트 코드가 지원되지 않는 작업을 사용했기 때문에 결국 문제가 생길 수 있습니다. 나는 IQueryable저장소 나 그와 동등한 계층을지나 "와일드로" 릴리스하지 말 것을 권장 한다.
Avish

302

가장 좋은 대답은 좋지만 두 인터페이스가 어떻게 다른지 설명하는 표현 트리는 언급하지 않습니다. 기본적으로 두 개의 동일한 LINQ 확장 세트가 있습니다. Where(), Sum(), Count(), FirstOrDefault()기능을 받아들이와 표현을 허용 하나, 등 모두 두 가지 버전이있다.

  • IEnumerable버전의 서명은 다음과 같습니다Where(Func<Customer, bool> predicate)

  • IQueryable버전의 서명은 다음과 같습니다Where(Expression<Func<Customer, bool>> predicate)

둘 다 동일한 구문을 사용하여 호출되기 때문에 실현하지 않고 두 가지를 모두 사용했을 것입니다.

예를 들어,이 Where(x => x.City == "<City>")모두에서 작동 IEnumerable하고IQueryable

  • 사용시 Where()IEnumerable컬렉션 컴파일러로 컴파일 된 함수를 전달Where()

  • 사용하는 경우 Where()IQueryable모음, 컴파일러에 식 트리를 전달합니다 Where(). 표현식 트리는 리플렉션 시스템과 유사하지만 코드 용입니다. 컴파일러는 코드를 쉽게 소화 할 수있는 형식으로 코드의 기능을 설명하는 데이터 구조로 코드를 변환합니다.

왜이 표현 트리에 신경을 쓰나요? Where()데이터를 필터링 하고 싶습니다 . 주된 이유는 EF와 Linq2SQL ORM이 모두 표현식 트리를 SQL로 직접 변환하여 코드가 훨씬 빠르게 실행될 수 있기 때문입니다.

아, 그것은 무료 성능 향상처럼 들립니다 AsQueryable(). 그 경우 어디에서나 사용해야 합니까? 아니요, IQueryable기본 데이터 공급자가 무언가를 할 수있는 경우에만 유용합니다. 정기적처럼 뭔가를 변환 List하는 것은 IQueryable당신에게 어떤 혜택을 제공하지 않습니다.


9
IMO 허용되는 답변보다 낫습니다. 그러나 나는 한 가지를 얻지 못합니다. IQueryable은 일반 객체에 이점을 제공하지 않지만 어떤 식 으로든 더 나쁩니 까? 그것이 아무런 이점을 제공하지 않는다면 IEnumerable을 선호하는 이유가 충분하지 않기 때문에 IQueryable을 사용하는 아이디어는 여전히 유효합니다.
Sergei Tachenov

1
Sergey, IQueryable은 IEnumerable을 확장하므로 IQueryable을 사용하면 IEnumerable 인스턴스화보다 메모리에 더 많이로드됩니다! 여기에 논쟁이 있습니다. ( stackoverflow.com/questions/12064828 / ... c ++ 내가 추정 할 수 있다고 생각했지만)
Viking

이 답변이 Sergei와 함께 최선의 답변임을 동의합니다 (허용 된 답변은 괜찮음). 나는 내 경험에 것을 추가 할 것 IQueryable만큼 잘하지 구문 분석 기능을하지 IEnumerable않습니다 : 예를 들어, 당신은의 요소를 알고 싶은 경우 DBSet<BookEntity>A의없는 List<BookObject>, dbSetObject.Where(e => !listObject.Any(o => o.bookEntitySource == e))예외가 발생합니다 : Expression of type 'BookEntity' cannot be used for parameter of type 'BookObject' of method 'Boolean Contains[BookObject] (IEnumerable[BookObject], BookObject)'. .ToList()후에 추가해야했습니다 dbSetObject.
장 데이비드 란츠

80

예, 둘 다 지연된 실행을 사용합니다. SQL Server 프로파일 러를 사용하여 차이점을 설명하겠습니다 ....

다음 코드를 실행할 때 :

MarketDevEntities db = new MarketDevEntities();

IEnumerable<WebLog> first = db.WebLogs;
var second = first.Where(c => c.DurationSeconds > 10);
var third = second.Where(c => c.WebLogID > 100);
var result = third.Where(c => c.EmailAddress.Length > 11);

Console.Write(result.First().UserName);

SQL Server 프로파일 러에서 다음과 같은 명령을 찾습니다.

"SELECT * FROM [dbo].[WebLog]"

1 백만 개의 레코드가있는 WebLog 테이블에 대해 해당 코드 블록을 실행하는 데 약 90 초가 걸립니다.

따라서 모든 테이블 레코드는 메모리에 객체로로드 된 다음 각 .Where ()와 함께 이러한 객체에 대한 메모리의 또 다른 필터가됩니다.

위의 예 (두 번째 줄) IQueryable대신에 사용할 경우 IEnumerable:

SQL Server 프로파일 러에서 다음과 같은 명령을 찾습니다.

"SELECT TOP 1 * FROM [dbo].[WebLog] WHERE [DurationSeconds] > 10 AND [WebLogID] > 100 AND LEN([EmailAddress]) > 11"

를 사용하여이 코드 블록을 실행하는 데 약 4 초가 걸립니다 IQueryable.

IQueryable에는 예제에서 지연된 실행이라고하는 Expression사용시 생성되기 시작하는 트리 표현식을 저장 하는 속성이 있으며 result,이 표현식은 데이터베이스 엔진에서 실행되도록 SQL 쿼리로 변환됩니다.


5
이것은 IEnumerable로 캐스팅 할 때 기본 IQueryable이 IQueryable 확장 메서드를 잃어 버리는 것을 가르쳐줍니다.
Yiping

56

둘 다 당신에게 연기 된 집행을 제공 할 것입니다.

어느 것이 다른 것보다 선호되는지는 기본 데이터 소스가 무엇인지에 달려 있습니다.

를 반환하면 IEnumerable런타임에서 LINQ to Objects를 사용하여 컬렉션을 쿼리합니다.

를 반환하면 IQueryable( IEnumerable실제로 구현 ) 쿼리를 기본 소스 (LINQ to SQL, LINQ to XML 등)에서 더 잘 수행 할 수있는 것으로 변환하는 추가 기능을 제공합니다.


30

일반적으로 다음을 권장합니다.

  • 메소드 IQueryable<T>를 사용하여 개발자가 실행하기 전에 리턴하는 쿼리를 세분화 할 수있게하려면 리턴하십시오.

  • IEnumerable열거 할 객체 세트를 전송하려면 리턴 하십시오.

IQueryable데이터에 대한 "쿼리"(원하는 경우 구체화 할 수 있음)를 상상해보십시오 . 은 IEnumerable당신이 열거 할 수있는 이상 (이미 수신 된 또는 생성 된) 개체의 집합입니다.


2
"IEnumerable이 아닌"열거 할 수 있습니다.
Casey

28

이전에 많은 이야기가 있지만 더 기술적 인 방법으로 뿌리로 돌아 왔습니다.

  1. IEnumerable 는 열거 할 수있는 메모리에있는 객체의 모음입니다. 메모리 내에서 반복 할 수있는 메모리 내 시퀀스입니다 ( foreach루프 내에서 쉽게 사용할 수 있지만, 계속 사용할 수는 IEnumerator있음). 그것들은 그대로 메모리에 상주합니다.
  2. IQueryable 최종 결과에 대해 열거 할 수있는 능력을 가진 어떤 시점에서 다른 것으로 번역 될 표현 트리 입니다 . 나는 이것이 대부분의 사람들을 혼란스럽게하는 것 같아요.

그들은 분명히 다른 의미를 가지고 있습니다.

IQueryableLINQ 집계 함수 (Sum, Count 등) 또는 ToList [Array, Dictionary 등의 릴리스 API가 호출 되 자마자 기본 쿼리 공급자가 다른 것으로 변환 할 식 트리 (단순히 쿼리)를 나타냅니다. ..]. 그리고 IQueryable또한 구현하는 객체 IEnumerable, IEnumerable<T>그래서 그들은 쿼리를 표현하는 경우 해당 쿼리의 결과를 반복 할 수있다. 이는 IQueryable이 쿼리 일 필요는 없음을 의미합니다. 올바른 용어는 표현 트리 입니다.

이제 이러한 표현식이 실행되는 방식과 전환 대상은 모두 쿼리 제공자 (우리가 생각할 수있는 표현식 실행기)에 달려 있습니다.

에서 엔티티 프레임 워크 (즉 신비 기본 데이터 소스 제공 업체 또는 쿼리 제공 업체입니다) 세계 IQueryable표현식은 네이티브로 번역되는 T-SQL의 쿼리. Nhibernate그들과 비슷한 일을합니다. 예를 들어 LINQ : IQueryable Provider 링크 작성에 설명 된 개념에 따라 고유 한 것을 작성할 수 있으며 제품 상점 제공자 서비스에 대한 사용자 정의 조회 API를 원할 수 있습니다.

따라서 기본적으로 IQueryable객체는 명시 적으로 릴리스하고 시스템에 객체를 SQL 등으로 다시 작성하고 이후 처리를 위해 실행 체인을 보내도록 지시 할 때까지 오래 지속됩니다.

실행 을 연기하는 것처럼 LINQ특정 API가 시퀀스 (동일한 Count, ToList 등)에 대해 호출 될 때마다 메모리에서 표현식 트리 체계를 유지하고 필요할 때만 실행으로 전송하는 기능입니다.

두 가지 모두의 올바른 사용법은 특정 사례에 직면 한 작업에 따라 크게 다릅니다. 잘 알려진 리포지토리 패턴의 경우 개인적으로을 반환하도록 선택합니다 IList. 즉 IEnumerable목록 (인덱서 등)입니다. 따라서 IQueryable코드의 다른 곳에서 저장소 및 IEnumerable 내에서만 사용하는 것이 좋습니다. 우려 분리 원칙을 IQueryable세분화하고 파괴 하는 테스트 가능성 우려에 대해서는 언급하지 않습니다 . 리포지토리 내에서 식을 반환하면 소비자는 원하는대로 지속성 계층을 사용할 수 있습니다.

엉망에 약간의 추가 :) (댓글의 토론에서)) 실제 유형이 아니기 때문에 메모리에있는 객체는 없습니다. 유형에 대한 마커입니다. 그러나 그것은 의미가 있습니다 (심지어 이유입니다 MSDN은 그것을 이런 식으로 넣어) 식 트리로 IQueryables 반면 메모리 컬렉션으로 IEnumerables 생각. 요점은 IQueryable 인터페이스가 IEnumerable 인터페이스를 상속하므로 쿼리를 나타내는 경우 해당 쿼리 결과를 열거 할 수 있다는 것입니다. 열거하면 IQueryable 개체와 관련된 식 트리가 실행됩니다. 따라서 실제로 메모리에 객체가 없으면 IEnumerable 멤버를 호출 할 수 없습니다. 어쨌든 비어 있지 않으면 거기에 들어갑니다. IQueryables는 데이터가 아니라 쿼리 일뿐입니다.


3
IEnumerables가 항상 메모리에 있다는 의견은 반드시 사실이 아닙니다. IQueryable 인터페이스는 IEnumerable 인터페이스를 구현합니다. 이 때문에 LINQ-to-SQL 쿼리를 나타내는 원시 IQueryable을 IEnumerable을 예상하는 뷰로 전달할 수 있습니다! 데이터 컨텍스트가 만료되었거나 MARS (다중 활성 결과 세트)에 문제가있는 것으로 놀랄 수 있습니다.

따라서 실제로 메모리에 객체가 없으면 IEnumerable 멤버를 호출 할 수 없습니다. 어쨌든 비어 있지 않으면 거기에 들어갑니다. IQueryables는 데이터가 아니라 쿼리 일뿐입니다. 그러나 나는 당신의 요점을 정말로 본다. 이것에 대한 의견을 추가하겠습니다.
Arman McHitarian

@AlexanderPritchard 그들 중 어느 것도 실제 유형이 아니기 때문에 메모리에있는 객체가 아니며 유형의 마커입니다. 그러나 IEnumerables를 인 메모리 컬렉션으로 생각하는 반면 IQueryables를 표현 트리로 생각하는 것이 합리적입니다. 요점은 IQueryable 인터페이스가 IEnumerable 인터페이스를 상속하므로 쿼리를 나타내는 경우 해당 쿼리의 결과를 열거 할 수 있다는 것입니다. 열거하면 IQueryable 개체와 관련된 식 트리가 실행됩니다.
Arman McHitarian

24

일반적으로 쿼리의 원래 정적 유형은 중요 할 때까지 유지하려고합니다.

이러한 이유로 IQueryable<>또는 대신 변수를 'var'로 정의 할 수 IEnumerable<>있으며 유형이 변경되지 않음을 알 수 있습니다.

로 시작하는 경우 IQueryable<>일반적 IQueryable<>으로을 변경해야 할 몇 가지 이유가있을 때까지 이를 유지하려고 합니다. 그 이유는 가능한 많은 정보를 쿼리 프로세서에 제공하기 때문입니다. 예를 들어 10 개의 결과 ()를 사용 Take(10)하려는 경우 쿼리 계획을 최적화하고 사용할 데이터 만 보낼 수 있도록 SQL Server가 그 사실을 알기를 원합니다.

에서 눈길을 끄는 이유는 유형을 변경하기 IQueryable<>IEnumerable<>당신의 구현 몇 가지 확장 기능을 호출하는 것을 수 있습니다 IQueryable<>특정 객체가 비효율적으로 처리하거나 핸들 할 수없는 하나를. 이 경우 호출하는 확장 함수가 클래스 대신 클래스 의 함수가되도록 유형을 IEnumerable<>(변수 유형에 할당 IEnumerable<>하거나 AsEnumerable확장 메서드를 사용하여) 로 변환 할 수 있습니다 .EnumerableQueryable


18

오용이 IEnumerable<T>LINQ 쿼리 성능에 크게 영향을 미치는 방법에 대한 간단한 소스 코드 샘플이 포함 된 블로그 게시물이 있습니다 ( Entity Framework : IQueryable vs. IEnumerable) .

더 깊이 파고 소스를 살펴보면 다음과 같은 확장 방법이 분명히 다른 것을 알 수 있습니다 IEnumerable<T>.

// Type: System.Linq.Enumerable
// Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll
public static class Enumerable
{
    public static IEnumerable<TSource> Where<TSource>(
        this IEnumerable<TSource> source, 
        Func<TSource, bool> predicate)
    {
        return (IEnumerable<TSource>) 
            new Enumerable.WhereEnumerableIterator<TSource>(source, predicate);
    }
}

그리고 IQueryable<T>:

// Type: System.Linq.Queryable
// Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll
public static class Queryable
{
    public static IQueryable<TSource> Where<TSource>(
        this IQueryable<TSource> source, 
        Expression<Func<TSource, bool>> predicate)
    {
        return source.Provider.CreateQuery<TSource>(
            Expression.Call(
                null, 
                ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(
                    new Type[] { typeof(TSource) }), 
                    new Expression[] 
                        { source.Expression, Expression.Quote(predicate) }));
    }
}

첫 번째는 열거 가능한 반복자를 반환하고 두 번째는 IQueryable소스에 지정된 쿼리 공급자를 통해 쿼리를 만듭니다 .


11

최근에 IEnumerablev. 문제가 발생 했습니다 IQueryable. 사용되는 알고리즘은 먼저 IQueryable일련의 결과를 얻기 위해 쿼리를 수행했습니다 . 그런 다음 foreach항목을 Entity Framework (EF) 클래스로 인스턴스화 하여 루프 로 전달했습니다 . 이 EF 클래스는 fromLinq to Entity 쿼리 의 절 에서 사용되어 결과가되었습니다 IEnumerable.

저는 EF와 Linq for Entities를 처음 접했기 때문에 병목 현상이 무엇인지 파악하는 데 시간이 걸렸습니다. MiniProfiling을 사용하여 쿼리를 찾은 다음 모든 개별 작업을 하나의 IQueryableLinq for Entities 쿼리로 변환했습니다. 실행하는 IEnumerable데 15 초가 IQueryable걸리고 0.5 초가 걸렸습니다. 세 개의 테이블이 관련되어 있었고, 이것을 읽은 후에는 IEnumerable쿼리가 실제로 3 개의 테이블 교차 제품을 형성하고 결과를 필터링 했다고 생각합니다 .

IQueryables를 일반적으로 사용하고 변경 사항을 측정 할 수 있도록 작업을 프로파일 링하십시오.


그 이유는 IQueryable 표현식이 EF에서 기본 SQL로 변환되어 IEnumerable 목록이 인 메모리 오브젝트 인 동안 DB에서 바로 실행되기 때문입니다. Count, Sum 또는 To ...와 같은 집계 함수를 호출하고 나중에 메모리에서 작동하면 어느 시점에서 DB에서 가져옵니다. IQueryableAPI 중 하나를 호출하면 메모리에 갇혀 있지만 그렇지 않은 경우 표현식을 레이어 스택 위로 전달하고 API 호출까지 필터를 사용할 수 있습니다. 잘 설계된 DAL은 잘 설계된 리포지토리로 이러한 종류의 문제를 해결할 것입니다.)
Arman McHitarian

10

나는 상충되는 응답으로 인해 (주로 IEnumerable을 둘러싼) 몇 가지 사항을 분명히하고 싶습니다.

(1) 인터페이스를 IQueryable확장합니다 IEnumerable. ( 오류없이 IQueryable예상되는 것을 보낼 수 있습니다 IEnumerable.)

(2) IQueryableIEnumerableLINQ는 결과 집합을 반복 할 때 지연로드를 시도합니다. (구현은 각 유형에 대한 인터페이스 확장 메소드에서 볼 수 있습니다.)

다시 말해, IEnumerables독점적으로 "메모리 내"가 아닙니다. IQueryables데이터베이스에서 항상 실행되는 것은 아닙니다. IEnumerable추상 데이터 공급자가 없으므로 메모리에 항목을로드해야합니다 (한 번 검색되면 지연 될 수 있음). IQueryablesLINQ-to-SQL과 같은 추상 공급자를 사용하지만 .NET 인 메모리 공급자 일 수도 있습니다.

샘플 사용 사례

(a) IQueryableEF 컨텍스트에서 와 같이 레코드 목록을 검색합니다 . (메모리에 기록이 없습니다.)

(b) IQueryable모델이 인 뷰로 전달 IEnumerable합니다. (유효가. IQueryable확장 IEnumerable.)

(c) 뷰에서 데이터 세트의 레코드, 하위 엔터티 및 속성을 반복하고 액세스합니다. (예외가 발생할 수 있습니다!)

가능한 문제

(1) IEnumerable게으른 로딩 시도 및 데이터 컨텍스트가 만료되었습니다. 공급자를 더 이상 사용할 수 없어서 예외가 발생했습니다.

(2) Entity Framework 엔터티 프록시가 활성화되어 있고 (기본값) 데이터 컨텍스트가 만료 된 관련 (가상) 개체에 액세스하려고합니다. (1)과 같습니다.

(3) 다중 활성 결과 세트 (MARS). 블록 IEnumerable내에서 반복하면서 foreach( var record in resultSet )동시에 액세스를 시도하는 record.childEntity.childProperty경우 데이터 세트와 관계 엔티티 모두의 지연로드로 인해 MARS로 끝날 수 있습니다. 연결 문자열에서 활성화되지 않은 경우 예외가 발생합니다.

해결책

  • 연결 문자열에서 MARS를 사용하면 안정적으로 작동한다는 것을 알았습니다. 잘 이해하고 명시 적으로 원하지 않는 한 MARS를 피하는 것이 좋습니다.

호출을 통해 쿼리를 실행하고 결과를 저장합니다. resultList = resultSet.ToList() 이것은 엔터티가 메모리에 있는지 확인하는 가장 간단한 방법 인 것 같습니다.

관련 엔터티에 액세스하는 경우에도 데이터 컨텍스트가 필요할 수 있습니다. 또는 엔티티 프록시 및 명시 적으로 Include관련된 엔티티를에서 비활성화 할 수 있습니다 DbSet.


9

“IEnumerable”과“IQueryable”의 주요 차이점은 필터 로직이 실행되는 위치입니다. 하나는 클라이언트 측 (메모리)에서 실행되고 다른 하나는 데이터베이스에서 실행됩니다.

예를 들어, 데이터베이스에 사용자에 대한 10,000 개의 레코드가 있고 활성 사용자 인 900 명을 예로 들어 보겠습니다.이 경우 "IEnumerable"을 사용하면 먼저 10,000 개의 레코드를 모두 메모리에로드하고 그런 다음 IsActive 필터를 적용하여 900 명의 활성 사용자를 반환합니다.

반면에 "IQueryable"을 사용하는 경우 데이터베이스에서 IsActive 필터를 직접 적용하여 900 명의 활성 사용자를 직접 반환합니다.

참조 링크


성능면에서 어느 것이 최적화되고 경량입니까?
Sitecore Sam

@Sam "IQueryable"은 최적화 및 경량화 측면에서 더 선호됩니다.
Tabish Usman

6

우리는 같은 방식으로 둘 다 사용할 수 있으며 성능면에서만 다릅니다.

IQueryable은 데이터베이스에 대해서만 효율적인 방식으로 실행됩니다. 전체 선택 쿼리를 작성하고 관련 레코드 만 가져옵니다.

예를 들어 이름이 'Nimal'로 시작 하는 상위 10 명의 고객을 확보 하려고합니다 . 이 경우 선택 쿼리는로 생성됩니다 select top 10 * from Customer where name like ‘Nimal%’.

그러나 IEnumerable을 사용하면 쿼리가 유사 select * from Customer where name like ‘Nimal%’하고 상위 10 개가 C # 코딩 수준에서 필터링됩니다 (데이터베이스에서 모든 고객 레코드를 가져 와서 C #으로 전달).


5

처음 두 가지 좋은 답변 외에도 (driis & Jacob의) :

IEnumerable 인터페이스는 System.Collections 네임 스페이스에 있습니다.

IEnumerable 개체는 메모리의 데이터 집합을 나타내며이 데이터를 앞으로 만 이동할 수 있습니다. IEnumerable 개체로 표시되는 쿼리는 즉시 완벽하게 실행되므로 응용 프로그램에서 데이터를 빠르게받습니다.

쿼리가 실행될 때 IEnumerable은 모든 데이터를로드하며, 필터링이 필요한 경우 필터링 자체가 클라이언트 측에서 수행됩니다.

IQueryable 인터페이스는 System.Linq 네임 스페이스에 있습니다.

IQueryable 객체는 데이터베이스에 대한 원격 액세스를 제공하며 데이터를 처음부터 끝까지 또는 반대 순서로 탐색 할 수 있습니다. 쿼리를 생성하는 과정에서 반환 된 개체는 IQueryable이며 쿼리가 최적화됩니다. 결과적으로 실행 중에 메모리 소비가 적고 네트워크 대역폭이 줄어들지 만 동시에 IEnumerable 개체를 반환하는 쿼리보다 약간 느리게 처리 될 수 있습니다.

무엇을 선택해야합니까?

전체 반환 데이터 집합이 필요한 경우 최대 속도를 제공하는 IEnumerable을 사용하는 것이 좋습니다.

반환 된 전체 데이터 집합이 필요하지 않고 일부 필터링 된 데이터 만 필요한 경우 IQueryable을 사용하는 것이 좋습니다.


0

위의 것 외에도 다음 IQueryable대신에 사용하면 예외가 발생할 수 있습니다 IEnumerable.

경우 다음은 잘 작동 products입니다 IEnumerable:

products.Skip(-4);

그러나 productsis IQueryable이고 DB 테이블에서 레코드에 액세스하려고하면이 오류가 발생합니다.

OFFSET 절에 지정된 오프셋은 음수가 아닐 수 있습니다.

다음 쿼리가 생성 되었기 때문입니다.

SELECT [p].[ProductId]
FROM [Products] AS [p]
ORDER BY (SELECT 1)
OFFSET @__p_0 ROWS

OFFSET은 음수 값을 가질 수 없습니다.

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