2

我想通过 EntityFramework 4 通过 WCF 服务从 SQL Express 2008 R2 服务器返回相对大量的记录到 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 一定要那么慢吗?

4

2 回答 2

5

您的查询并不简单,它包含很多连接(由于Includes),更重要的是它可能会返回大量重复数据,特别是如果包含的导航属性是集合:https ://stackoverflow.com/a/5522195 /270591

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

您的测量结果(在对您问题的评论中)证实了这一点,即在同一上下文中的第二个查询非常快。在这种情况下,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

使用这种方法时,必须注意,即使相关对象具有相同的键,它们也会被创建为单独的对象——启用更改跟踪并非如此,因为附加到上下文将避免这种重复。

因此,可能会有更多的对象被加载到内存中。如果这会适得其反并且实际上会进一步降低性能,或者它是否仍然表现更好,那就是一个测试问题。

于 2012-04-04T13:28:35.510 回答
0

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

于 2012-04-05T09:15:14.550 回答