Entity Framework 初始化速度慢——有什么办法可以更快地启动它?

37
我的 EF 4.3.1 模型有200多个表格。初始启动非常慢,需要几分钟时间。使用 DotTrace 捕获的性能分析显示一些可怕的算法/可扩展性选择深入框架中,由下面的许多方法调用和3600万个 IEnumerable.Contains() 调用所证明。这是一个片段,所有这些都是由对数据库执行的第一个查询触发的(未来的查询不会这样做,并且很好)。

enter image description here

我该如何修改我的模型,使得这个过程更加容易? 我能否以某种方式进行预编译? 更好的方法是,EF团队是否可以解决这些问题或开源框架,以便我可以解决这些问题? 或者至少修复Warapper的拼写错误? :)
编辑:触发此问题的一个具体EF调用基本上是var db = new MyDbContext(); db.Personnel.Where(a => a.Login == login).SingleOrDefault();。 此外,EF迁移Seed() AddOrUpdate生成的堆栈与效果相同。 更完整的堆栈跟踪,可能会给出更多上下文,位于此处:Fuller Stack Trace 编辑:一些相关链接:

编辑2:现在他们刚刚开源了代码,看起来这一行:

//Filter the 1:1 foreign key associations to the ones relating the sets used in these cell wrappers.
oneToOneForeignKeyAssociationsForThisWrapper =
    oneToOneForeignKeyAssociationsForThisWrapper.Where(
        it => (it.AssociationEndMembers.All(endMember => entityTypes.Contains(endMember.GetEntityType()))));

需要进行改进的是第一个部分。它使用了一个O(n^2)算法,但我还没有仔细研究过。

编辑3:令人高兴的是,EF6中的改进正在修复这段代码:http://entityframework.codeplex.com/discussions/396130


1
你能提供创建这个追踪的C#样例代码吗? - Erik Philips
@Erik Philips:当然可以(编辑问题),但这很微不足道。 - Scott Stafford
2
首先应该查看性能考虑(Entity Framework),如果你还没有去过那里的话 - 顺便检查一下版本号。 - AakashM
@AakashM:谢谢。我看了,很好的阅读材料。至少他们知道它很慢。;) - Scott Stafford
在这个问题中:http://stackoverflow.com/q/18807355/325727 我遇到了一个类似的问题,其中UnityIoC导致了数百万次的框架调用,如DotNetTrace所示。不幸的是,这个问题从未得到解决,我们最终放弃了Unity。 - JK.
3个回答

23

在EF6之前,对于较大的模型,视图生成已知速度较慢。目前的解决方案是使用预生成视图。这样,在设计时生成视图,避免了运行时的工作。为此,请下载EF Power Tools并选择“优化实体数据模型”。它将向您的项目添加一个包含视图的C#文件。缺点是每次模型更改时都需要执行此操作。注意:使用该工具生成视图所需的时间与运行时生成视图所需的时间大致相同(因此有时需要耐心等待)。这里是关于EF Power Tools的帖子,可能会有所帮助:http://blogs.msdn.com/b/adonet/archive/2011/05/18/ef-power-tools-ctp1-released.aspx

Edit

最近我创建了一种不需要预先生成视图但更方便使用的解决方案(请注意,仅适用于EF6)- http://blog.3d-logic.com/2013/12/14/using-pre-generated-views-without-having-to-pre-generate-views-ef6/


谢谢,我会调查一下并尝试在这里发布结果。您认为在未来版本中是否可以进行软件改进以加快此过程,还是计算量太大,已经优化到极致了(这意味着我必须切割或删除一些内容)? - Scott Stafford
很高兴听到这个消息!祝你好运...如果可能的话,我很乐意提供支持。 - Scott Stafford
不,非常感谢您的建议。很高兴看到你们在 SO 上搜索。 - Scott Stafford
有没有一种方法可以提取堆栈跟踪?调试窗口或弹出窗口中没有任何内容,只有这个消息。我在此报告的线程上发布了:http://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d/view/Discussions#4307 - Scott Stafford
EF Power Tools的链接已经失效。 - Michael Freidgeim
显示剩余4条评论

12

以下是另一种方法。虽然需要一些手动操作,但实际上更适合您想要使用MsBuild的情况。而不是使用Power Tools创建视图(很抱歉这些工具对您无效),您可以手动创建它们 - 下面是步骤:

  • 首先,您需要获取上下文的artifacts。 您需要所有-csdl、ssdl和msl文件。 您可以使用EdmxWriter来获取这些文件。请注意,EdmxWriter返回将三个文件组合在一起的edmx文件,因此您需要拆分它们。以下是此步骤的代码(请注意,命名空间特定于EF4,如果您考虑使用EF5和.NET Framework 4.5,您需要相应更改它们或仅选择本地名称而不是完全限定名称的元素):

    var ms = new MemoryStream();
    using (var writer = XmlWriter.Create(ms))
    {
        EdmxWriter.WriteEdmx(new Context(), writer);
    }

    ms.Position = 0;

    var xDoc = XDocument.Load(ms);

    var ssdl = xDoc.Descendants("{http://schemas.microsoft.com/ado/2009/02/edm/ssdl}Schema").Single();
    var csdl = xDoc.Descendants("{http://schemas.microsoft.com/ado/2008/09/edm}Schema").Single();
    var msl = xDoc.Descendants("{http://schemas.microsoft.com/ado/2008/09/mapping/cs}Mapping").Single();

    ssdl.Save("Context.ssdl");
    csdl.Save("Context.csdl");
    msl.Save("Context.msl");
  • 如果你有生成的数据模型,你可以使用EdmGen工具来创建视图。由于我们在这里是手动创建,所以需要从VS命令提示符中执行此操作。以下是用于生成视图的命令:
EdmGen /mode:ViewGeneration /incsdl:Context.csdl  /inmsl:Context.msl /inssdl:Context.ssdl /outviews:Context.Views.cs
  • 将生成的文件添加到您的项目中。

如果您想将视图生成与构建系统集成,还有一种有趣的选择 - 使用 T4 模板。该模板会处理上述步骤。您可以在这里找到更多关于此方法的详细信息http://blogs.msdn.com/b/adonet/archive/2008/06/20/how-to-use-a-t4-template-for-view-generation.aspx。唯一的问题是该示例不适用于 CodeFirst 方法,因此需要进行一些修改,这应该不难。

我实际上创建了针对 Code First 的 T4 模板。您可以在我的博客文章中找到下载链接:http://blog.3d-logic.com/2012/05/28/entity-framework-code-first-and-pre-generated-views/

这些模板现在可以在 Visual Studio Code Gallery 上获得。以下是具有所有详细信息的帖子链接:http://blog.3d-logic.com/2012/06/13/entity-framework-codefirst-view-generation-templates-on-visual-studio-code-gallery/


1
Pawel目前的C# T4模板链接是:http://visualstudiogallery.msdn.microsoft.com/ae7730ce-ddab-470f-8456-1b313cd2c44d - Scott Stafford
嗨,Pawel。这段代码需要做哪些更改才能与EF6一起使用?var ssdl = .... 抛出InvalidOperationException:序列不包含任何元素。 - Goran
@Goran - EF5的视图与EF6不兼容,因此您无法使用EdmGen为EF6生成视图。如果您正在使用CodeFirst,则可以创建EF6特定的模板来生成视图-请参见此http://blog.3d-logic.com/2013/10/17/ef6-codefirst-view-generation-t4-template-for-c-updated-for-ef6-rtm/以获取更多详细信息。或者,您可以使用EF Power Tools Beta 4为CodeFirst和Edmx for EF6创建视图-请参见此(http://blogs.msdn.com/b/adonet/archive/2013/10/12/ef-power-tools-beta-4-available.aspx)帖子以获取更多详细信息。 - Pawel
@Pawel,感谢您在这个领域的努力。EF Power不支持Visual Studio 2015。难道没有其他解决方案来保存EF6的ssdl、csdl和msl文件吗?例如使用System.Data.Resources.SSDLSchema_2.xsd文件? - harsini
很抱歉,我不理解你的问题。xsd描述了Xml文档的结构,不能用于保存任何内容。PowerTools的大部分功能已经移至随VS一起提供的EF Designer中。 - Pawel
显示剩余2条评论

1

在当前版本的Entity Framework (6.1)中,实际上视图生成非常快速。正在准备另一个更广泛的缓存解决方案:https://entityframework.codeplex.com/workitem/1876。您可以等待此补丁被接受,或者如果您足够勇敢,可以自行应用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接