IUumerable <T> ile IQueryable <T> Karşılaştırması


1084

Geri dönüş IQueryable<T>ile IEnumerable<T>diğeri arasındaki fark ne zaman tercih edilmeli?

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;

Yanıtlar:


1778

Evet, her ikisi de size ertelenmiş infaz verecektir .

Aradaki fark, IQueryable<T>LINQ-to-SQL (gerçekten LINQ.-to-her şey) çalışmasına izin veren arabirimdir. Bu nedenle, sorgunuzu bir üzerinde daha da hassaslaştırırsanız, mümkünse IQueryable<T>bu sorgu veritabanında yürütülür.

Bu IEnumerable<T>durumda, orijinal sorgu ile eşleşen tüm nesnelerin veritabanından belleğe yüklenmesi gerektiği anlamına gelen LINQ-to-object olacaktır.

Kodda:

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

Bu kod, SQL'i yalnızca altın müşterileri seçecek şekilde yürütür. Öte yandan, aşağıdaki kod veritabanında orijinal sorguyu yürütür ve ardından bellekteki altın olmayan müşterileri filtreler:

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

Bu oldukça önemli bir farktır ve IQueryable<T>birçok durumda çalışmak sizi veritabanından çok fazla satır döndürmekten kurtarabilir. Eğer kullanıyorsanız: Başka başlıca örneği sayfalama yapıyor Takeve Skipüzerinde IQueryable, sadece satır sayısı istenen alacak; bunu bir IEnumerable<T>seferde yapmak tüm satırlarınızın belleğe yüklenmesine neden olur.


32
Harika bir açıklama. IEnumerable'ın IQueryable'a tercih edileceği durumlar var mı?
fjxx

8
Hafıza Nesnesini sorgulamak için IQueryable kullanıyorsanız, IEnumerable ve IQueryable arasında herhangi bir fark olmayacağını söyleyebiliriz?
Tarik

11
UYARI: IQueryable belirtilen optimizasyon nedeniyle cazip bir çözüm olsa da, havuzun veya hizmet katmanının ötesine geçmesine izin verilmemelidir. Bu veritabanı "LINQ ifadeleri istifleme" neden yükü korumak için.
Yorro

48
@fjxx Evet. Orijinal sonucunuzda tekrarlanan filtreleme istiyorsanız (birkaç sonuç). IQueryable arabiriminde bunu yapmak veritabanına birkaç gidiş dönüş yapacak, burada IEnumerable üzerinde yapmak gibi bellekte filtreleme yapacak (veri miktarı BÜYÜK değilse)
Per Hornshøj-Schierbeck

34
Tercih başka bir nedeni IEnumerableiçin IQueryabledeğil tüm LINQ işlemleri tüm LINQ sağlayıcıları tarafından desteklenen olmasıdır. Ne yaptığınızı bildiğiniz sürece IQueryable, sorgunun çoğunu LINQ sağlayıcısına (LINQ2SQL, EF, NHibernate, MongoDB vb.) İletmek için kullanabilirsiniz. Ancak, başka bir kodun istediklerinizi yapmasına izin verirseniz, IQueryablebir yerde bazı istemci kodları desteklenmeyen bir işlem kullandığı için sonunda sorun yaşarsınız. IQueryableDepoyu veya eşdeğer katmanı geçmeden "vahşi doğaya" bırakmama tavsiyesine katılıyorum .
Avish

302

Üst yanıt iyidir, ancak iki arayüzün "nasıl" değiştiğini açıklayan ifade ağaçlarından bahsetmez. Temel olarak, iki özdeş LINQ uzantısı seti vardır. Where(), Sum(), Count(), FirstOrDefault()İşlevlerini kabul diğeri ifadeleri kabul: biri, vs hepsi iki sürümü var.

  • IEnumerableVersiyon imzadır:Where(Func<Customer, bool> predicate)

  • IQueryableVersiyon imzadır:Where(Expression<Func<Customer, bool>> predicate)

Muhtemelen her ikisini de farkında olmadan kullanıyorsunuz çünkü her ikisi de aynı sözdizimi kullanılarak çağrılıyor:

örneğin Where(x => x.City == "<City>")hem çalışır IEnumerableveIQueryable

  • Kullanıldığında Where(), bir de IEnumerabletoplama derleyici için derlenmiş bir işlevi geçirirWhere()

  • Kullanırken Where(), bir de IQueryablekoleksiyon, derleyici bir ifade ağacı geçer Where(). Bir ifade ağacı yansıma sistemine benzer ancak kod içindir. Derleyici, kodunuzu, kodunuzun ne yaptığını kolayca sindirilebilen bir biçimde açıklayan bir veri yapısına dönüştürür.

Neden bu ifade ağacı ile uğraşasınız ki? Sadece Where()verilerime filtre uygulamak istiyorum. Bunun ana nedeni hem EF hem de Linq2SQL ORM'lerin ifade ağaçlarını doğrudan kodunuzun çok daha hızlı çalışacağı SQL'e dönüştürebilmesidir.

Oh, kulağa ücretsiz bir performans artışı gibi geliyor AsQueryable(), bu durumda her yerde mi kullanmalıyım? Hayır, IQueryableyalnızca temeldeki veri sağlayıcısı onunla bir şeyler yapabiliyorsa yararlıdır. Düzenli gibi bir şey dönüştürme ListTo IQueryablesize bir fayda vermeyecektir.


9
IMO kabul edilen cevaptan daha iyi. Ancak, bir şey almıyorum: IQueryable normal nesneler için herhangi bir fayda sağlamaz, Tamam, ama herhangi bir şekilde daha kötü mü? Çünkü herhangi bir fayda sağlamazsa, IEnumerable'ı tercih etmek için yeterli bir neden yoktur, bu nedenle IQueryable'ı her yerde kullanma fikri geçerliliğini korur.
Sergei Tachenov

1
Sergey, IQueryable IEnumerable'ı genişletir, böylece IQueryable'ı kullanırken belleğe bir IEnumerable örneğinden daha fazla yüklersiniz! İşte bir argüman. ( stackoverflow.com/questions/12064828/… c ++ Ben bunu tahmin edebileceğimi düşündüm)
Viking

Sergei ile bunun en iyi cevap olduğu konusunda anlaşmak (kabul edilen cevap iyi olsa da). Benim deneyimlerime göre, bu eklersiniz IQueryableyanı sıra değil ayrıştırma işlevleri yapar IEnumerableyapar: Örneğin, bir elementleri olduğunu öğrenmek istiyorsanız DBSet<BookEntity>bir olmayan List<BookObject>, dbSetObject.Where(e => !listObject.Any(o => o.bookEntitySource == e))bir istisna atar: Expression of type 'BookEntity' cannot be used for parameter of type 'BookObject' of method 'Boolean Contains[BookObject] (IEnumerable[BookObject], BookObject)'. Ben eklemek zorunda .ToList()sonra dbSetObject.
Jean-David Lanz

80

Evet, her ikisi de ertelenmiş yürütme kullanır. SQL Server profiler kullanarak farkı gösterelim ....

Aşağıdaki kodu çalıştırdığımızda:

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 profil oluşturucuda şuna eşit bir komut buluruz:

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

Bu kod bloğunun 1 milyon kaydı olan bir WebLog tablosunda çalıştırılması yaklaşık 90 saniye sürer.

Böylece, tüm tablo kayıtları belleğe nesne olarak yüklenir ve sonra her bir .Where () ile bu nesnelere karşı bellekte başka bir filtre olur.

Yukarıdaki örnekte kullanmak IQueryableyerine IEnumerable(ikinci satır):

SQL Server profil oluşturucuda şuna eşit bir komut buluruz:

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

Bu kod bloğunu kullanarak çalıştırmak yaklaşık dört saniye sürer IQueryable.

IQueryable, örneğimizde (ertelenmiş yürütme olarak adlandırılır) Expressionkullanıldığında oluşturulmaya başlayan bir ağaç ifadesini depolayan bir özelliğe sahiptir resultve sonunda bu ifade, veritabanı motorunda çalıştırmak için bir SQL sorgusuna dönüştürülür.


5
Bu, IEnumerable'a yayın yaparken bana öğretir, temeldeki IQueryable, IQueryable uzatma yöntemini kaybeder.
Yiping

56

Her ikisi de size ertelenmiş infaz verecek, evet.

Hangisi diğerine tercih edilirse, temeldeki veri kaynağınızın ne olduğuna bağlıdır.

Bir i döndürüldüğünde IEnumerable, çalışma zamanı otomatik olarak koleksiyonunuzu sorgulamak için LINQ'u Nesnelere kullanmaya zorlar.

Bir IQueryable(bu arada uygular) döndürmek IEnumerable, sorgunuzu temel kaynakta daha iyi performans gösterebilecek bir şeye (LINQ to SQL, LINQ to XML, vb.) Çevirmek için ekstra işlevsellik sağlar.


30

Genel olarak aşağıdakileri tavsiye ederim:

  • Yürütmeden IQueryable<T>önce döndürdüğünüz sorguyu hassaslaştırmak için yönteminizi kullanarak geliştiriciyi etkinleştirmek istiyorsanız, geri dönün.

  • IEnumerableNumaralandırılacak bir dizi Nesneyi taşımak istiyorsanız geri dönün .

IQueryableBunun ne olduğunu hayal edin - veriler için bir "sorgu" (isterseniz inceleyebilirsiniz). An IEnumerable, üzerinde numaralandırabileceğiniz (önceden alınmış veya oluşturulmuş) bir nesneler kümesidir.


2
"Numaralanabilir," değil "IEnumerable olabilir."
Casey

28

Daha önce çok şey söylendi, ancak daha teknik bir şekilde köklere dönelim:

  1. IEnumerable bellekte numaralandırabileceğiniz bir nesne topluluğudur - yinelemeyi mümkün kılan bir bellek içi dizilimdir ( yalnızca foreachbirlikte kullanabilmenize rağmen döngü içinde kolaylaştırır IEnumerator). Hafızada olduğu gibi yaşıyorlar.
  2. IQueryable bir noktada , nihai sonuç üzerinde numaralandırma yeteneği olan başka bir şeye çevrilecek olan bir ifade ağacıdır . Sanırım çoğu insanın kafasını karıştıran şey bu.

Açıkçası farklı çağrışımları var.

IQueryableLINQ toplama işlevleri (Sum, Count, vb.) veya ToList [Array, Dictionary, gibi yayın API'leri çağrıldığında temel sorgu sağlayıcı tarafından başka bir şeye çevrilecek bir ifade ağacını (sadece bir sorgu) temsil eder. ..]. Ve IQueryablenesneler de uygular IEnumerable, IEnumerable<T>böylece bir sorguyu temsil ederlerse o sorgunun sonucu yinelenebilir. Bu, IQueryable'ın yalnızca sorgu olması gerekmediği anlamına gelir. Doğru terim ifade ağaçları olmasıdır .

Şimdi bu ifadelerin nasıl yürütüldüğünü ve neye dönüştüklerini, sorgu sağlayıcıları (bunları düşünebileceğimiz ifade yürütücüler) olarak adlandırıyoruz.

In Varlık Framework (yani mistik temel veri kaynağı sağlayıcı veya sorgu sağlayıcı olan) dünyaya IQueryableifadeleri yerli çevrilir T-SQL sorguları. Nhibernateonlarla benzer şeyler yapıyor. Örneğin, LINQ'da oldukça iyi açıklanan kavramları izleyerek kendi kodunuzu yazabilirsiniz : Örneğin, bir IQueryable Sağlayıcısı bağlantısı oluşturma ve ürün deposu sağlayıcı hizmetiniz için özel bir sorgulama API'sına sahip olmak isteyebilirsiniz.

Temelde, IQueryablenesneler, onları açıkça serbest bırakıp sisteme bunları SQL'e veya başka bir şekilde yeniden yazmasını ve yürütme zincirini ileriye doğru işlemek için göndermesini söyleyene kadar tamamen inşa ediliyor.

İçin Sanki ertelenmiş yürütme bir var LINQbellekte ifade ağacı şeması yukarı kaldırıp sadece sekans (aynı Kont, ToList, vs.) karşı denir her belirli API'leri talep üzerine icra içine göndermek için özellik.

Her ikisinin de doğru kullanımı, özel durum için karşılaştığınız görevlere bağlıdır. Şahsen geri dönmeyi tercih ettiğim iyi bilinen depo deseni için IList, IEnumerableListeler (dizinleyiciler ve benzeri) üzerinde. Bu yüzden IQueryablesadece depolarda ve kodda başka bir yerde IEnumerable içinde kullanmak benim tavsiyem . Ahlaksızlık ile ilgili endişelerin ayrılması ilkesini IQueryablebozan ve bozan endişeler hakkında söylememek . Depolardan bir ifade döndürürseniz, tüketiciler istedikleri gibi kalıcılık katmanıyla oynayabilirler.

Dağınıklığa küçük bir ek :) (yorumlardaki bir tartışmadan)) Bunların hiçbiri, gerçek türler olmadıkları için bellekteki nesneler değildir, bir tür işaretleyicilerdir - eğer bu kadar derine gitmek istiyorsanız. Ancak IEnumerables'ı bellek içi koleksiyonlar olarak düşünürken, IQueryables'ı ifade ağaçları olarak düşünmek mantıklıdır (ve bu yüzden MSDN bile bu şekilde koydu). Buradaki nokta, IQueryable arabiriminin IEnumerable arabirimini devralır, böylece bir sorguyu temsil ederse, bu sorgunun sonuçları numaralandırılabilir. Numaralandırma, bir IQueryable nesnesiyle ilişkili ifade ağacının yürütülmesine neden olur. Yani, aslında, nesneyi hafızaya almadan IEnumerable üyelerini gerçekten çağıramazsınız. Eğer yaparsanız, zaten boş değilse, oraya girecektir. IQueryable'lar sadece sorgulardır, veriler değildir.


3
IEnumerable'ların her zaman bellekte olduğu yorumu zorunlu olarak doğru değildir. IQueryable arabirimi IEnumerable arabirimini uygular. Bu nedenle, bir LINQ-SQL sorgusu temsil eden bir ham IQueryable doğrudan bir IEnumerable bekliyor bir görünüm geçirebilirsiniz! Veri içeriğinizin süresinin dolduğunu veya MARS (birden çok etkin sonuç kümesi) ile ilgili sorunlara yol açtığınızı görünce şaşırabilirsiniz.

bu nedenle, aslında nesneyi hafızaya almadan IEnumerable üyelerini gerçekten çağıramazsınız. Eğer yaparsanız, zaten boş değilse, oraya girecektir. IQueryable'lar sadece sorgulardır, veriler değildir. Ama gerçekten ne demek istediğini anlıyorum. Bu konuda bir yorum ekleyeceğim.
Arman McHitarian

@AlexanderPritchard bunların hiçbiri bellekteki nesneler değil, çünkü gerçek türler değiller, bir tür belirteçler - eğer o kadar derine inmek istiyorsanız. Ancak IEnumerables'ı bellek içi koleksiyonlar olarak düşünürken, IQueryables'ı ifade ağaçları olarak düşünmek mantıklıdır (ve bu yüzden MSDN bile bu şekilde koydu). Buradaki nokta, IQueryable arabiriminin IEnumerable arabirimini devralır, böylece bir sorguyu temsil ederse, bu sorgunun sonuçları numaralandırılabilir. Numaralandırma, bir IQueryable nesnesiyle ilişkili ifade ağacının yürütülmesine neden olur.
Arman McHitarian

24

Genel olarak, sorgunun önemli olana kadar orijinal statik türünü korumak istersiniz.

Bu nedenle değişkeninizi ya yerine 'var' olarak tanımlayabilirsiniz ya IQueryable<>da IEnumerable<>türü değiştirmediğinizi bileceksiniz.

Bir ile başlarsanız IQueryable<>, IQueryable<>değiştirmek için zorlayıcı bir neden olana kadar genellikle bir olarak tutmak istersiniz . Bunun nedeni, sorgu işlemcisine mümkün olduğunca fazla bilgi vermek istemenizdir. Örneğin, yalnızca 10 sonuç (kullanacaksınız) kullanacaksanız, Take(10)SQL Server'ın bunu bilmesini istersiniz, böylece sorgu planlarını optimize edebilir ve size yalnızca kullanacağınız verileri gönderebilir.

A zorlayıcı neden türünü değiştirmek IQueryable<>için IEnumerable<>size uygulanması bazı uzatma fonksiyonunu çağırarak durumu ortaya çıkabilir IQueryable<>belirli nesnede verimsiz işlemek veya kolları değil ya. Bu durumda, çağıracağınız uzantı işlevlerinin sınıf yerine sınıftaki işlevler olmasını sağlamak için, türü türe dönüştürmek isteyebilirsiniz IEnumerable<>( örneğin , bir tür değişkenine atayarak IEnumerable<>veya AsEnumerableuzantı yöntemini kullanarak ) .EnumerableQueryable


18

Kötüye kullanımının IEnumerable<T>LINQ sorgu performansını nasıl önemli ölçüde etkileyebileceğine ilişkin kısa kaynak kodu örneği içeren bir blog yazısı vardır : Entity Framework: IQueryable vs. IEnumerable .

Daha derine iner ve kaynaklara bakarsak, açıkça farklı uzantı yöntemlerinin ortaya çıktığını görebiliriz 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);
    }
}

ve 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) }));
    }
}

Birincisi numaralandırılabilir yineleyici döndürür ve ikincisi IQueryablekaynakta belirtilen sorgu sağlayıcısı aracılığıyla sorgu oluşturur .


11

Geçenlerde bir sorun koştum IEnumerablev. IQueryable. Kullanılan algoritma önce bir IQueryablesonuç kümesi elde etmek için bir sorgu gerçekleştirdi . Bunlar daha sonra foreachöğeler Entity Framework (EF) sınıfı olarak başlatılan bir döngüye geçirildi . Daha sonra bu EF sınıfı, fromsonuca neden olan bir Linq to Entity sorgusunun yan tümcesinde kullanıldı IEnumerable.

EF ve Linq for Entities için oldukça yeniyim, bu yüzden darboğazın ne olduğunu anlamak biraz zaman aldı. MiniProfiling kullanarak, sorguyu buldum ve sonra tek tek tüm işlemleri tek bir IQueryableLinq for Entities sorgusuna dönüştürdü. IEnumerable15 saniye sürdü ve IQueryableçalıştırmak için 0.5 saniye sürdü. İlgili üç tablo vardı ve bunu okuduktan sonra, IEnumerablesorgunun aslında üç tablo çapraz ürünü oluşturduğuna ve sonuçları filtrelediğine inanıyorum .

IQueryables'ı genel bir kural olarak kullanmaya çalışın ve değişikliklerinizi ölçülebilir hale getirmek için çalışmanızı tanıtın.


Bunun nedeni, IQueryable ifadelerinin EF'de yerel bir SQL'e dönüştürülmesidir ve IEnumerable listeleri bellek içi nesnelerken doğrudan DB'de yürütülür. Count, Sum veya herhangi bir To ... gibi toplama işlevlerini çağırdığınızda DB'den bir noktada getirilirler ve daha sonra bellekte çalışırlar. IQueryableBu API'lardan birini aradıktan sonra bellekte takılı kalırlar, ancak değilse, ifadeyi katman yığınından geçirebilir ve API çağrısına kadar filtrelerle oynayabilirsiniz. İyi tasarlanmış bir Depo olarak iyi tasarlanmış DAL bu tür sorunları çözecektir;)
Arman McHitarian

10

Görünüşte çelişkili yanıtlar (çoğunlukla IEnumerable çevresindeki) nedeniyle birkaç şeyi açıklığa kavuşturmak istiyorum.

(1) arayüzü IQueryablegenişletir IEnumerable. ( Hatasız IQueryablebeklediğiniz bir şeye gönderebilirsiniz IEnumerable.)

(2) her ikisi de IQueryableve IEnumerableiterating sonuç kümesi üzerinde yavaş yükleme girişimi LINQ. (Uygulamanın, her tür için arabirim uzantısı yöntemlerinde görülebileceğini unutmayın.)

Başka bir deyişle, IEnumerablessadece "bellek içi" değildir. IQueryablesher zaman veritabanında yürütülmez. IEnumerablesoyut veri sağlayıcısı olmadığından bir şeyleri belleğe yüklemelidir (bir kez alındığında, muhtemelen tembel olarak). IQueryablessoyut bir sağlayıcıya (LINQ-to-SQL gibi) güvenmekle birlikte, bu aynı zamanda .NET bellek içi sağlayıcı da olabilir.

Örnek kullanım örneği

(a) IQueryableEF bağlamından kayıtların listesini alın. (Bellekte kayıt yok.)

(b) IQueryableModeli olan bir görünüme geçin IEnumerable. (Geçerli. IQueryableUzanıyor IEnumerable.)

(c) Veri kümesinin kayıtlarına, alt varlıklarına ve özelliklerine görünümden yineleyin ve erişin. (İstisnalara neden olabilir!)

Olası Sorunlar

(1) IEnumerableTembel yükleme girişimleri ve veri içeriğinizin süresi dolmuş. Sağlayıcı artık kullanılamadığı için istisna atıldı.

(2) Entity Framework varlık proxy'leri etkinleştirilir (varsayılan) ve süresi dolmuş bir veri bağlamıyla ilgili (sanal) bir nesneye erişmeye çalışırsınız. (1) ile aynı.

(3) Çoklu Aktif Sonuç Kümeleri (MARS). IEnumerableBir foreach( var record in resultSet )blokta yineleme yapıyorsanız ve aynı anda erişmeye çalışırsanız record.childEntity.childProperty, hem veri kümesinin hem de ilişkisel varlığın tembel yüklenmesi nedeniyle MARS ile sonuçlanabilir. Bu, bağlantı dizenizde etkin değilse bir istisnaya neden olur.

Çözüm

  • Bağlantı dizesinde MARS etkinleştirmenin güvenilmez şekilde çalıştığını gördüm. İyi anlaşılmadığı ve açıkça istenmedikçe MARS'tan kaçınmanızı öneririm.

Sorguyu yürütün ve sonuçları çağırarak depolayın. resultList = resultSet.ToList() Bu, varlıklarınızın bellekte olmasını sağlamanın en kolay yolu gibi görünüyor.

İlişkili varlıklara eriştiğiniz durumlarda yine de bir veri bağlamına ihtiyacınız olabilir. Ya bu, ya da varlık proxy'lerini ve açıkça Includeilgili varlıkları devre dışı bırakabilirsiniz DbSet.


9

“IEnumerable” ve “IQueryable” arasındaki temel fark, filtre mantığının yürütüldüğü yerdir. Biri istemci tarafında (bellekte) ve diğeri veritabanında yürütülür.

Örneğin, veritabanımızda bir kullanıcı için 10.000 kaydın olduğu bir örneği düşünebilir ve diyelim ki aktif kullanıcılar olan sadece 900 kayıt diyelim, bu durumda “IEnumerable” kullanırsak önce 10.000 kaydın tümünü belleğe yükler ve daha sonra 900 aktif kullanıcıyı döndüren IsActive filtresini uygular.

Diğer yandan aynı durumda “IQueryable” kullanırsak, doğrudan oradan 900 aktif kullanıcıyı döndürecek olan IsActive filtresini doğrudan veritabanına uygulayacaktır.

Referans Bağlantısı


hangisi performans açısından optimize edilmiş ve hafiftir?
Sitecore Sam

@Sam "IQueryable" optimize ve hafif olması açısından daha çok tercih ediliyor.
Tabish Usman

6

Her ikisini de aynı şekilde kullanabiliriz ve performansta sadece farklıdırlar.

IQueryable, veritabanında yalnızca verimli bir şekilde yürütülür. Bu, tüm seçme sorgusunu oluşturduğu ve yalnızca ilgili kayıtları aldığı anlamına gelir.

Örneğin , adı 'Nimal' ile başlayan ilk 10 müşteriyi almak istiyoruz . Bu durumda seçme sorgusu olarak oluşturulur select top 10 * from Customer where name like ‘Nimal%’.

Ancak IEnumerable kullandıysak, sorgu gibi olurdu select * from Customer where name like ‘Nimal%’ve ilk on C # kodlama düzeyinde filtrelenecektir (tüm müşteri kayıtlarını veritabanından alır ve C # 'a geçirir).


5

İlk 2 gerçekten iyi cevaba ek olarak (driis ve Jacob tarafından):

IEnumerable arabirimi System.Collections ad alanındadır.

IEnumerable nesnesi, bellekteki bir veri kümesini temsil eder ve bu veriler üzerinde yalnızca ilerleyebilir. IEnumerable nesnesi tarafından temsil edilen sorgu hemen ve tamamen yürütülür, böylece uygulama verileri hızlı bir şekilde alır.

Sorgu yürütüldüğünde, IEnumerable tüm verileri yükler ve filtrelememiz gerekirse, filtrelemenin kendisi istemci tarafında yapılır.

IQueryable arabirimi System.Linq ad alanında bulunur.

IQueryable nesnesi, veritabanına uzaktan erişim sağlar ve veriler arasında başından sonuna veya doğrudan sırayla gezinmenizi sağlar. Bir sorgu oluşturma sürecinde, döndürülen nesne IQueryable, sorgu en iyileştirilir. Sonuç olarak, yürütülmesi sırasında daha az bellek, daha az ağ bant genişliği tüketilir, ancak aynı zamanda IEnumerable nesnesini döndüren bir sorgudan biraz daha yavaş işlenebilir.

Ne seçeceksin?

Döndürülen tüm veri kümesine ihtiyacınız varsa, maksimum hızı sağlayan IEnumerable'ı kullanmak daha iyidir.

Döndürülen tüm veri kümesine İHTİYACINIZ OLMADAN, ancak yalnızca filtrelenmiş bazı verilere ihtiyacınız varsa, IQueryable'ı kullanmak daha iyidir.


0

Yukarıdakilere ek olarak, aşağıdakiler IQueryableyerine kullanırsanız istisnalar alabileceğinizi belirtmek ilginçtir IEnumerable:

Aşağıdakiler cezası çalışır productsbir olduğunu IEnumerable:

products.Skip(-4);

Ancak eğer productsbir olduğunu IQueryableve bir DB tablodan erişim kayıtları çalışıyor, o zaman bu hatayı alırsınız:

OFFSET deyiminde belirtilen ofset negatif olmayabilir.

Bunun nedeni aşağıdaki sorgunun oluşturulmasıdır:

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

ve OFFSET'in negatif bir değeri olamaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.