实体框架 - 计数中的绩效

时间:2015-08-31 09:33:46

标签: c# performance entity-framework

我对实体框架的性能提出了一些小问题。

这样的东西
using (MyContext context = new MyContext())
{
    Document DocObject = context.Document.Find(_id);
    int GroupCount = context.Document.Where(w=>w.Group == DocObject.Group).ToList().Count();
}

在我的数据库中大约需要2秒钟(大约30k数据集),而这一个

using (MyContext context = new MyContext())
{
    Document DocObject = context.Document.Find(_id);
    int GroupCount = context.Document.Where(w=>w.Group == DocObject.Group).Count();
}

需要0.02秒。

当我的10个文档的过滤器有20秒等待时,我检查了我的代码,并将其更改为在ToList()之前不使用Count()

为什么这行与ToList()

需要2秒的任何想法

5 个答案:

答案 0 :(得分:23)

调用ToList()然后调用Count()

  • 对您的数据库执行整个SELECT FROM WHERE
  • 然后将所有生成的实体实现为.Net对象
  • 创建一个包含所有结果的新List<T>对象
  • 返回刚刚创建的.Net列表的Count属性的结果

针对Count()致电IQueryable将:

  • 对您的数据库执行SELECT COUNT FROM WHERE
  • 返回包含行数的Int32

显然,如果您只对项目数量感兴趣(不是项目本身),那么您不应该首先致电ToList(),因为它将无需任何资源。

答案 1 :(得分:4)

是的,ToList()将评估结果(从数据库中检索对象),如果不使用ToList(),则不会从数据库中检索对象。

Linq-To-Entities默认使用LazyLoading。

它的作用是这样的; 当您使用Linq-To-Entities查询基础数据库连接时,您将获得一个代理对象,您可以在其上执行许多操作(计数为1)。这意味着您不会立即从DB获取所有数据,而是在评估时从数据库中检索对象。评估对象的一种方法是使用ToList()。

也许你应该阅读this

答案 2 :(得分:4)

因为ToList()会在数据库中查询整个对象(这样做会SELECT *),然后你会在内存中的列表中使用Count()所有记录,如果您在Count()上使用IQueryable(而不是List),则EF会将其转换为简单的SELECT COUNT(*) SQL查询

答案 3 :(得分:2)

您的第一个查询未完全转换为sql - 当您致电.ToList().Count()时,您基本上是说“全部下载,将其实现为POCO并调用名为Count()的扩展方法”当然,一段时间。

然而,您的第二个查询被转换为类似select count(*) from Documents where GroupId = @DocObjectGroup的内容,执行起来要快得多,而且您没有实现任何内容,只是简单的标量。

答案 4 :(得分:1)

使用扩展方法Enumerable.ToList()将从IEnumerable<T>源集合构造一个新的List对象,这意味着执行ToList()会产生相关的成本。