EF 4.1 Code-first在我的应用程序中执行比常规EF慢3倍的查询

Che*_*hev 11 .net c# entity-framework entity-framework-4 entity-framework-4.1

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

注意:请记住,对EF 4.1的此更改纯粹是为了学习.如果你想知道我的需求是什么导致我升级,那就没有了.我只是想做有趣的事情.

我复制了项目并进行了升级,因此我将拥有相同的项目,但具有不同的实体框架实现.在新项目中,我使用名为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代码)之一.

DbContext 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并开始我的快乐方式,但我真的很感兴趣,如果可能有我错过的东西.

Che*_*hev 5

UPDATE

由于最近的一些发展,我完全重新回答了这个答案.

由于微软的实体框架团队试图复制我的问题,我回过头来回顾我的步骤以更好地帮助缩小问题范围.自从我提出这个问题以来已经有一段时间了,而且我现在对事情的了解比我当时要好得多.

而不是回去尝试运行一些非常旧的代码,我决定从头开始使用一个简单的测试项目.我将一个带有两个表的简单数据库放在一起,并将它们映射到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" />
Run Code Online (Sandbox Code Playgroud)

然后,我为数据库填充了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" />
Run Code Online (Sandbox Code Playgroud)

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

除了代码优先生成映射元数据所花费的额外时间之外,查询时间没有差异.在初始查询之后,两个版本的EF执行几乎相同.我即将解决这个问题,因为这个问题不可重复,但后来我注意到我在这个问题上做了一些可怕的事情.我.AsEnumerable()在查询之前打过电话.如果你还不知道它是做什么的,那将导致ENTIRE实体集合被拉入内存,然后查询将作为LINQ-to-Objects而不是LINQ-to-Entities应用于那里.

这意味着我正在将整个表吸入内存然后在那里对它进行LINQ.如果SQL服务器与您的网站在同一台计算机上,您可能不会注意到差异,但在许多情况下,这将是一个巨大的问题.在我的情况下,它确实导致了性能损失.

我回到了我的测试中,并.AsEnumerable()在查询之前将它们放置了.

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

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

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

我在三次查询后停止了它,因为每次查询等待大约两分钟是令人难以忍受的.我似乎无法生成我在问题中显示的3x缓慢问题,但仅代码显着慢.EDMX方法只需要两分钟即可完成一个查询,而仅使用代码的方法一直需要两分钟.