c# - 列表查询比 IQueryable 快 20 倍?

标签 c# performance linq list iqueryable

这是我今晚设置的测试。它是为了证明一些不同的东西,但结果并不像我预期的那样。

我在一个 IQueryable 上运行一个包含 10000 个随机查询的测试,在测试时我发现如果我在一个列表上做同样的事情,我的测试速度会快 20 倍。

见下文。我的 CarBrandManager.GetList 最初返回一个 IQueryable,但现在我首先发出一个 ToList(),然后速度更快。

谁能告诉我为什么我看到这么大的不同?

var sw = new Stopwatch();
sw.Start();

int queries = 10000;

//IQueryable<Model.CarBrand> carBrands = CarBrandManager.GetList(context);
List<Model.CarBrand> carBrands = CarBrandManager.GetList(context).ToList();

Random random = new Random();
int randomChar = 65;

for (int i = 0; i < queries; i++)
{
    randomChar = random.Next(65, 90);
    Model.CarBrand carBrand = carBrands.Where(x => x.Name.StartsWith(((char)randomChar).ToString())).FirstOrDefault();
}

sw.Stop();
lblStopWatch.Text = String.Format("Queries: {0} Elapsed ticks: {1}", queries, sw.ElapsedTicks);

最佳答案

这里可能存在两个问题。第一:从 GetList(context) 返回什么类型的集合并不明显。 ,除了它实现的知识IQueryable .这意味着当您评估结果时,它很可能是创建一个 SQL 查询,将该查询发送到数据库,并将结果具体化为对象。或者它可能正在解析 XML 文件。或者下载 RSS 提要或调用互联网上的 OData 端点。这些显然比简单地过滤内存中的短列表要花费更多的时间。 (毕竟,真正有多少汽车品牌?)

但是让我们假设它返回的实现实际上是一个 List ,因此您正在测试的唯一区别是它是否被转换为 IEnumerable或作为 IQueryable .比较 Enumerable 上的方法签名类的扩展方法与 Queryable 上的扩展方法.当您将列表视为 IQueryable 时,您传入的是 Expression s,需要评估,而不仅仅是 Func可以直接运行。

当您使用 Entity Framework 等自定义 LINQ 提供程序时,这使框架能够评估实际的表达式树并从中生成 SQL 查询和具体化计划。但是,LINQ to Objects 只想计算内存中的 lambda 表达式,因此它必须使用反射或将表达式编译为 Func。 s,两者都对性能有很大的影响。

您可能只想调用 .ToList().AsEnumerable()在结果集上强制使用 Func s,但来自 information hiding观点这将是一个错误。您会假设您知道从 GetList(context) 返回的数据方法是某种内存中的对象。目前可能是这种情况,也可能不是。无论如何,它不是为 GetList(context) 定义的契约(Contract)的一部分。方法,因此你不能假设它总是那样。您必须假设您返回的类型很可能是您可以查询的类型。尽管目前可能只有十几个汽车品牌可供搜索,但有可能有一天会有数千个(我在这里谈论的是编程实践,不一定是说汽车行业就是这种情况).因此,您不应该假设下载整个汽车列表并在内存中过滤它们总是会更快,即使现在恰好是这种情况。

如果CarBrandManager.GetList(context)可能会返回一个由自定义 LINQ 提供程序(如 Entity Framework 集合)支持的对象,那么您可能希望将数据转换为 IQueryable:即使您的基准测试显示使用列表快 20 倍,但差异是如此之大小到没有用户能够分辨出差异。有一天,您可能会通过调用 .Where().Take().Skip() 看到几个数量级的性能提升。并且只从数据存储中加载你真正需要的数据,而如果你调用 .ToList(),你最终会将整个表加载到你的系统内存中。马上开始。

但是,如果您知道 CarBrandManager.GetList(context)将始终返回一个内存列表(顾名思义),应将其更改为返回 IEnumerable<Model.CarBrand>而不是 IQueryable<Model.CarBrand> .或者,如果您使用的是 .NET 4.5,可能是 IReadOnlyList<Model.CarBrand>IReadOnlyCollection<Model.CarBrand> ,取决于您愿意强制执行的契约(Contract) CarManager遵守。

关于c# - 列表查询比 IQueryable 快 20 倍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13078208/

相关文章:

java - Power BI 嵌入式 : Get Report details API responds with 400 Bad request

c# - mysql存储过程批量插入

python - 为什么 dictionary.keys() 中的键比字典中的键慢?

c# - HtmlAgilityPack 使用 Linq for windows phone 8.1 平台

c# - LINQ to SQL : Group, 计数、求和。我很困惑

c# - Global.asax 中的自动事件连接

java - Java中避免ClassCastException的策略

java - 如何在 MySQL 中创建不重复的随机用户 ID?

java - 如果 profiler 不是答案,我们还有什么其他选择?

c# - 以编程方式为 LINQ 生成类型化数据集 - 缺少 "Metadata file"?