c# - 在我的应用程序中,EF 4.1 代码优先执行查询比常规 EF 慢 3 倍

标签 c# .net entity-framework entity-framework-4 entity-framework-4.1

我有一个宠物项目(一个简单的论坛应用程序),我用它来测试所有最新的 .NET 技术,最近我开始玩弄 Entity Framework Code-First。这个应用程序已经有一个现有的 EF 解决方案,其中一个 EDMX 文件映射到一个现有的数据库,我的所有实体都是自动生成的。到目前为止,该解决方案效果很好。

注意:请记住,对 EF 4.1 的这一更改纯粹是为了学习。如果你想知道我的需求是什么导致我升级,没有任何需求。我只是想好玩。

我复制了该项目并进行了升级,因此我将拥有相同的项目但具有不同的 Entity Framework 实现。在新项目中,我使用了一个名为 Entity Framework Power Tools 的 Visual Studio 扩展来从我现有的数据库中生成 POCO 和 DbContext。一切都完美无缺。我在大约 30 分钟的时间内编译了该应用程序。相当令人印象深刻。

但是,我现在在运行该应用程序时注意到,查询执行速度比以前慢了大约 3 倍。知道我可能错过了什么吗?

下面是两种解决方案的详细信息,以及两种解决方案的 LINQPad 测量结果。 (点击图片查看全尺寸)

EF 4.0 详细信息

这是我的 EF 4.0 数据模型的快照。它切断了顶部和底部的一些实体,但你明白了。

http://www.codetunnel.com/content/images/EF41question/1.jpg 这是针对我的 EF 4.0 数据模型的 LINQPad 测试。

http://www.codetunnel.com/content/images/EF41question/2.jpg 请注意,执行该查询需要 2.743 秒。

EF 4.1 详细信息

这是我的 EF 4.1 数据模型的快照。由于它是纯代码,因此我将展示 DbContext 类以及一个实体和一个实体本身的映射类之一(流畅的 API 代码)。

数据库环境 http://www.codetunnel.com/content/images/EF41question/3.jpg TopicMap(流畅的API配置) http://www.codetunnel.com/content/images/EF41question/4.jpg 主题(POCO 实体) http://www.codetunnel.com/content/images/EF41question/5.jpg 这是针对我的 EF 4.1 模型的 LINQPad 测试。

http://www.codetunnel.com/content/images/EF41question/6.jpg 请注意,这次查询花费了 6.287 秒来执行,而且是完全相同的查询。第一次运行需要 30 多秒。如果我转到 LINQPad 中的 SQL 和 IL 选项卡,生成的 SQL 和 IL 代码对于两个数据模型都是相同的。这真的让我很伤心。在实际应用程序中,EF 4.1 的速度太慢以至于无法使用。

我对这两个模型运行了相同的 LINQ 查询。该查询获取普通论坛用户的所有主题,按最后回复日期(如果没有回复,则按主题发布日期)降序排列。

显然,我可以回到 EF 4.0 并继续我的快乐之路,但我真的很想知道我是否遗漏了什么。

最佳答案

更新

由于最近的一些发展,我正在重新审视这个答案。

由于 Microsoft Entity Framework 团队的一些询问试图重复我的问题,我返回并回顾我的步骤以更好地帮助缩小问题范围。我问这个问题已经有一段时间了,我现在比那时更了解事情了。

我没有回头尝试运行一些非常旧的代码,而是决定从头开始做一个简单的测试项目。我将一个简单的数据库与两个表放在一起,并将它们映射到一个 EF 4.0 设计器文件。

这生成了一个像这样的连接字符串:

<add name="EFTestEntities" connectionString="metadata=res://*/Entities.csdl|res://*/Entities.ssdl|res://*/Entities.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\sqlexpress;initial catalog=EFTest;integrated security=True;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

然后我用 1000 行测试主题和每个主题的 10 行回复填充了数据库。完成这项工作后,我对一个非常基本的查询进行了计时,该查询与我的主要问题中的查询非常相似。然后我复制了测试项目并使用 Entity Framework Power Tools 修改了它扩展来生成我的模型对象和 DbContext。我唯一修改的是连接字符串,用于删除项目中有设计器文件时引用的元数据,因此它看起来像这样:

<add name="EFTestContext" providerName="System.Data.SqlClient" connectionString="Data Source=.\sqlexpress;Initial Catalog=EFTest;Integrated Security=True;Pooling=False" />

然后我运行了与设计器完全相同的查询。

除了代码优先生成映射元数据所需的时间稍微多一些外,查询时间没有差异。在初始查询之后,两个版本的 EF 的性能几乎相同。我正要解决这个不可重现的问题,但后来我注意到我在这个问题上做了一些可怕的事情。我在查询之前调用了 .AsEnumerable()。如果您还不知道它的作用,这将导致整个实体集合被拉入内存,然后查询将作为 LINQ-to-Objects 而不是 LINQ-to-Entities 在那里应用。

这意味着我将整个表吸入内存,然后在那里对其执行 LINQ。如果 SQL Server 与您的网站位于同一台机器上,您可能不会注意到其中的差异,但在很多情况下这将是一个大问题。在我的例子中,它确实导致了性能损失。

我回到我的测试,并在查询之前使用 .AsEnumerable() 运行它们。

现在我预计时间会变慢,因为我的 LINQ 查询没有被翻译成表达式树并在数据库中执行。但是,似乎我确实在我的问题中重现了这个问题。仅代码版本的返回速度要慢得多。这实际上很奇怪,因为它们应该运行相同。我对它们运行速度比针对 IQueryable 的查询慢并不感到惊讶,但现在它们针对 IEnumerable 运行时,两者之间存在很大差异。通过向表中添加越来越多的数据,我能够扩大两者之间的差异。

我继续向数据库添加了 5000 个主题,每个主题有 30 个回复。所以现在总共有 6000 个主题行和 165000 个回复行。首先,我使用适当的 LINQ-to-Entities 运行查询:

如您所见,仍然没有区别。然后我使用 .AsEnumerable() 针对 LINQ-to-Objects 运行查询。

我在三个查询后停止了它,因为每个查询等待大约两分钟是非常痛苦的。我似乎无法产生我在问题中显示的 3x 慢问题,但仅代码速度要慢得多。 EDMX 方法只需不到两分钟即可完成一个查询,而纯代码方法始终需要两分钟以上。

关于c# - 在我的应用程序中,EF 4.1 代码优先执行查询比常规 EF 慢 3 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7604571/

相关文章:

.NET TimeZoneInfo 关于夏令时的错误

c# - .NET 在为 WCF 服务生成类型时加载寻找另一个版本的程序集

c# - EF6 和 EF4.1 在文件层次结构中的区别

c# - 在 Visual Studio 2010 中引用 mscorlib

c# - 来自同一类型的两个对象的组合键

asp.net-mvc-3 - 建立与 SQL Server 的连接时发生与网络相关或特定于实例的错误 - ASP.NET MVC Entity Framework

c# - ASP.Net C# 路由; HTTP处理器;和 HttpModule 不工作

c# - 为什么我会收到此错误?无法从中加载类型

c# - 我可以以编程方式更改 asp.net 控件的 ID - ASP.NET

c# - 这是对 goto 的明确使用吗?