EntityFramework:使用~11000记录在IQueryable上调用ToList()需要10秒

时间:2012-04-04 10:52:46

标签: linq entity-framework entity-framework-4 sql-server-2008-r2 tolist

我想从SQL Express 2008 R2服务器返回相对大量的记录,通过EntityFramework 4到WCF客户端通过WCF服务。我的测试表目前包含大约11.000条记录。 LINQ查询就像这样简单:

Database DB = new Database(); // create object context
var retValue = DB.Entities.Persons
        .Include("District")
        .Include("District.City")
        .Include("District.City.State")
        .Include("Nationality")

return retValue.ToList();

这需要大约10秒钟才能完成。

在SQL Server Managament Studio中执行时,相同的SELECT查询所需的时间不到1秒。

EF中是否必须缓慢?

2 个答案:

答案 0 :(得分:5)

您的查询不简单,它包含大量连接(由于Include),更重要的是它可能会返回大量重复数据,特别是如果包含的导航属性是集合:{​​{3 }}

时间消耗部分是对象实现,并在数据库的结果返回到实体框架上下文时将实体附加到上下文。

这可以通过您的测量(在您的问题的评论中)确认在同一上下文中的第二个查询非常快。在这种情况下,EF将对数据库执行查询,但不需要再次实现对象,因为它们仍然附加到上下文。

如果在第二个上下文中运行第二个查询,则生成的实体必须附加到新上下文 - 此步骤再次变慢(也通过测量确认)。

这可能是EF 的查询实际上很慢并且与原始SQL查询相比增加了大量开销的一点。 EF需要创建许多数据结构,为变更跟踪和管理上下文中的对象标识做好准备,这会花费额外的时间。

我能看到改善性能的唯一方法是禁用更改跟踪(假设您不需要它来进行操作)。在EF 4.0 / ObjectContext中,它将是:

Database DB = new Database();
DB.Entities.Persons.MergeOption = MergeOption.NoTracking;
// MergeOption is in System.Data.Objects namespace

使用这种方法时,必须要注意的是,相关对象将被创建为单独的对象,即使它们具有相同的密钥 - 这与启用的更改跟踪不同,因为附加到上下文将避免这种重复。

因此,可能会有更多对象加载到内存中。如果这会产生反作用,实际上性能会降低甚至更高,或者它仍然表现更好是一个测试问题。

答案 1 :(得分:0)

这很可能是因为与查询执行相比,查询编译(许多包含的LINQ查询 - >要使用的SQL)在EF中非常慢。您可以通过CPU分析代码来验证这是否是问题。考虑使用较少的包含+多个较小的查询,使用已编译的查询或升级到最新的EF5 beta。