实体框架太慢了.我有什么选择?

Vac*_*ano 87 .net performance orm entity-framework

我遵循了"不要过早优化"的口头禅并使用Entity Framework编写了我的WCF服务.

但是,我描述了性能和实体框架太慢了.(我的应用程序在大约1.2秒内处理2条消息,其中我正在重写的(传统)应用程序同时执行5-6条消息.(旧应用程序调用sprocs进行数据库访问.)

我的分析指向实体框架占用每条消息的大部分时间.

那么,我的选择是什么?

  • 那里有更好的ORM吗?
    (只支持正常读取和写入对象的东西,并且它很快...)

  • 有没有办法让实体框架更快?
    (注意:当我说速度更快时,我的意思是从长远来看,而不是第一次调用.(第一次调用很慢(消息为15秒),但这不是问题.我只需要它快速休息的消息.)

  • 一些神秘的第三选项,将帮助我提高我的服务速度.

注意:我的大多数数据库交互都是创建和更新.我做的很少选择和删除.

小智 71

事实上,像Entity Framework这样的产品总是很慢而且效率低下,因为它们正在执行更多的代码.

我也觉得很愚蠢,人们建议应该优化LINQ查询,查看生成的SQL,使用调试器,预编译,执行许多额外步骤等,即浪费大量时间.没有人说 - 简化!每个人都希望通过采取更多步骤(浪费时间)来进一步复杂化.

常识性方法根本不是使用EF或LINQ.使用纯SQL.没有什么问题.仅仅因为程序员之间存在群体心态,并且他们感觉到在那里使用每一件新产品的冲动,并不意味着它是好的或者它会起作用.大多数程序员认为,如果他们将大型公司发布的每一段新代码都包含在内,那么它就会让他们成为一个更聪明的程序员; 根本不是真的.智能编程主要是关于如何以更少的麻烦,不确定性以及在最短的时间内完成更多工作.记住 - 时间!这是最重要的元素,所以试着想方设法不要浪费它来解决坏/臃肿代码中的问题,只是为了符合一些奇怪的所谓"模式"

放松,享受生活,从编码中休息一下,停止使用额外的功能,代码,产品,"模式".生命是短暂的,你的代码的生命甚至更短,它肯定不是火箭科学.删除LINQ,EF等层,你的代码将高效运行,可以扩展,是的,它仍然很容易维护.过多的抽象是一种糟糕的"模式".

这就是解决问题的方法.

  • 这是用洗澡水把婴儿扔出去的.你优化了瓶颈,把EF扔掉是很愚蠢的,因为它在一些地方太慢了,而在大多数其他地方都很快.为什么不同时使用?EF处理存储过程和原始SQL就好了.我刚刚转换了一个LINQ-to-SQL查询,花了10秒多的时间进入SP需要大约1秒钟,但我不会把所有LINQ-to-SQL都抛出去.它在其他更简单的情况下节省了大量时间,代码更少,错误空间更小,并且查询经过编译器验证并与数据库匹配.更少的代码更容易维护,更少的错误空间. (150认同)
  • -1."EF总是很慢而且效率低下." 我不明白为什么你会断言这样的事情是绝对真理.拥有更多层将会使速度变慢,但是这种差异是否通常是完全取决于数据量和正在执行的查询类型等情况.对我来说,这与说"C#总是缓慢而低效"是一回事,因为它比C++更具抽象性.然而,许多人选择使用它,因为生产率的提高远远超过了性能损失(如果有的话).这同样适用于EF (56认同)
  • 普通的SQL =易于维护?对于具有大量业务逻辑的大型应用程序来说,情况并非如此 编写复杂的可重用SQL并不是一件容易的事.就我个人而言,我遇到了EF的一些性能问题,但是这些问题根本无法与RAD相关的正确ORM的好处进行比较并且保持DRY(如果涉及任何复杂程度). (47认同)
  • + 10 ^ 100过多的抽象是一个糟糕的'模式' (12认同)
  • 总体而言,你的建议很好,但我不认为放弃EF或其他抽象是正确的,因为它们在10%的时间内都不能正常工作. (10认同)
  • 对于它的价值,我有点重新审视我在这个旧评论中显示的观点.我们已经抛弃了EF,通过Dapper支持SQL查询,并使用自定义更改跟踪器进行插入/更新/删除.它有缺点,但只是*知道*某些事情的执行和行为,因为你控制过程的所有部分是非常有价值的.我仍然不认为EF是坏的,但我可能不会接受我知道需要高性能和复杂数据访问的项目的依赖性. (8认同)
  • 您不能以通用的方式编写能够显着简化大型软件问题的内容,而这种方式不会带来显着的性能成本.必须有大量代码来处理问题所适用的各种情况.一方面需要权衡通用和问题,另一方面要有性能. (5认同)
  • 肖恩 - 我完全同意你的看法.简单的ADO.Net代码是我在.Net编程生涯的10年中遇到的最快的代码.所有这些ORM框架都会导致执行额外的代码,额外的代码需要额外的时间来执行和额外的资源.我看到这些框架的唯一优势是它们可以节省开发时间,但代价是使应用程序变得更慢而且代码更重.就个人而言,我觉得当开发人员懒得编写ADO.Net代码时,他们会使用这些框架.在我看来,这是一个简单的方法,或者它可能只是来自项目经理的压力. (4认同)
  • 好吧,让我们花10到100个开发时间来创建一些使用经过验证的真实工具.这个太慢的论点几乎总是因为开发人员不了解如何优化代码. (3认同)
  • 阿门...复杂的混淆.. (3认同)
  • 100% 同意这个答案。老实说,我觉得 ORM 和 EF 是一种倒退。我在开发方面有 20 年的经验,并且曾在超大型系统上工作过。SQL 的速度和效率比 EF 快几个数量级。EF 仅适用于对 SQL 不够了解且需要通过臃肿架构层层掌控的开发人员。 (2认同)

J. *_*hon 45

您应该首先分析实体框架实际发布的SQL命令.根据您的配置(POCO,自我跟踪实体),有很多优化空间.您可以使用该ObjectSet<T>.ToTraceString()方法调试SQL命令(在调试和发布模式之间不应该有所不同).如果您遇到需要进一步优化的查询,您可以使用一些预测来为EF提供有关您要完成的内容的更多信息.

例:

Product product = db.Products.SingleOrDefault(p => p.Id == 10);
// executes SELECT * FROM Products WHERE Id = 10

ProductDto dto = new ProductDto();
foreach (Category category in product.Categories)
// executes SELECT * FROM Categories WHERE ProductId = 10
{
    dto.Categories.Add(new CategoryDto { Name = category.Name });
}
Run Code Online (Sandbox Code Playgroud)

可以替换为:

var query = from p in db.Products
            where p.Id == 10
            select new
            {
                p.Name,
                Categories = from c in p.Categories select c.Name
            };
ProductDto dto = new ProductDto();
foreach (var categoryName in query.Single().Categories)
// Executes SELECT p.Id, c.Name FROM Products as p, Categories as c WHERE p.Id = 10 AND p.Id = c.ProductId
{
    dto.Categories.Add(new CategoryDto { Name = categoryName });
}
Run Code Online (Sandbox Code Playgroud)

我只是输入了这个,所以这不完全是如何执行的,但是如果你告诉它关于查询的所有信息,EF实际上做了一些很好的优化(在这种情况下,我们需要类别 - 名).但这不像是预先加载(db.Products.Include("Categories")),因为投影可以进一步减少要加载的数据量.

  • 这种反应听起来很合理,直到您意识到匿名类型无法在定义它们的方法之外访问.如果要加载复杂对象而不是编写megamoth,则需要将新的匿名类型反序列化为某种POCO.再说一遍,这几乎听起来很合理,直到你意识到这样做,你基本上重写了你自己的实体框架.哪个是废话. (37认同)
  • 有趣且有用的回复,相当一段时间后仍然有效.@Doug:这并不是废话,因为你只需优化(使用投影)那些你确实需要使用额外收益的查询.EF和POCO为您提供合理的默认值,这非常好! (11认同)
  • 这导致我的速度提高了15倍-20倍. (5认同)
  • 我用来感觉ORM是未来.他们才有意义,直到我开始使用它们.然后我找到[Dapper](https://github.com/StackExchange/dapper-dot-net).现在,当看到这样的解决方案时,我会畏缩复杂性如何迅速提升.在C#中编写抽象的SQL是没有办法度过的. (3认同)
  • @Doug大多数应用程序都具有仅视图场景的视图模型,对吗?拔出数据时,也可能会进行尽可能多的映射。 (2认同)

Ste*_*ham 35

一个建议是仅对单记录CRUD语句使用LINQ to Entity Framework.

对于更复杂的查询,搜索,报告等,编写存储过程并将其添加到实体框架模型,如MSDN中所述.

这是我在几个网站上采用的方法,它似乎是生产力和性能之间的良好折衷.实体框架并不总是为手头的任务生成最有效的SQL.而不是花时间弄清楚原因,为更复杂的查询编写存储过程实际上为我节省了时间.一旦熟悉了该过程,将存储过程添加到EF模型中并不是一件容易的事.当然,将其添加到模型中的好处是,您可以获得使用ORM带来的所有强类型优势.


Jul*_*anR 14

如果您纯粹是在获取数据,那么当您告诉EF不跟踪它所获取的实体时,这对性能有很大帮助.通过使用MergeOption.NoTracking来完成此操作.EF将生成查询,执行它并将结果反序列化为对象,但不会尝试跟踪实体更改或任何此类性质.如果查询很简单(没有花太多时间等待数据库返回),我发现将其设置为NoTracking可以使查询性能提高一倍.

有关MergeOption枚举的信息,请参阅此MSDN文章:

身份解析,状态管理和变更跟踪

这似乎是关于EF性能的好文章:

绩效和实体框架

  • 在任何人这样做之前,在这里阅读可能是个好主意.http://stackoverflow.com/questions/9259480/entity-framework-mergeoption-notracking-bad-performance (9认同)

Sea*_*ron 6

你说你已经分析了应用程序.你有没有对ORM进行过分析?有一个来自Ayende的EF分析器,它将突出显示您可以优化EF代码的位置.你可以在这里找到它:

http://efprof.com/

请记住,如果需要获得性能,可以在ORM旁边使用传统的SQL方法.

如果有更快/更好的ORM?根据您的对象/数据模型,您可以考虑使用其中一个微型ORM,例如Dapper,MassivePetaPoco.

Dapper网站发布了一些比较基准,可以让您了解它们与其他ORM的比较.但值得注意的是,微型ORM不支持EF和NH等完整ORM的丰富功能集.

您可能想看一下RavenDB.这是一个非关系数据库(再次来自Ayende),它允许您直接存储POCO而无需映射.RavenDB针对读取进行了优化,通过消除操作模式和将对象映射到该模式的需要,使开发人员的工作变得更加轻松.但是,请注意这是使用ORM方法的一种截然不同的方法,这些方法在产品的网站中列出.


归档时间:

查看次数:

109683 次

最近记录:

7 年,5 月 前