我对实体框架的性能提出了一些小问题。
像
这样的东西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()
答案 0 :(得分:23)
调用ToList()
然后调用Count()
:
SELECT FROM WHERE
List<T>
对象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()
会产生相关的成本。