过滤内存收集:IQueryable提供更好的性能

本文关键字:更好 性能 IQueryable 内存 过滤 | 更新日期: 2023-09-27 17:49:55

假设我有一个内存中的集合(Persons),我必须对其应用一些过滤条件。

var distinctproductKeys = persons.Where(d => d.productsDictionary != null)
                                 .SelectMany(d => d.productsDictionary.Keys)
                                 .Distinct();

vs。如果我在应用过滤器之前使用IQueryable

var distinctproductKeys = persons.AsQueryable()
                                 .Where(d => d.productsDictionary != null)
                                 .SelectMany(d => d.productsDictionary.Keys)
                                 .Distinct();

我读到,一旦你有你的集合在内存中,IQueryable和IEnumerable给出相同的性能。但是运行这两个查询,我观察到IQueryable版本更快。有人能告诉我为什么吗?

过滤内存收集:IQueryable提供更好的性能

我不知道你是如何测试你的性能,但要记住的主要事情是当使用IQueryableIEnumerable时,它们都会给你延迟执行

的区别在于IQueryable是允许LINQ-to- sql (LINQ. sql)的接口。(任何事情)都可以工作。因此,如果您进一步细化IQueryable查询,该查询将在数据库中执行,如果可能的话。

对于IEnumerable,它将是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在很多情况下可以避免从数据库返回太多行。另一个典型的例子是分页:如果你在IQueryable上使用Take和Skip,你只会得到请求的行数;在IEnumerable上这样做会导致所有的行都被加载到内存中。