我遵循了“不要过早优化”的口号,并使用实体框架编写了我的WCF服务。
但是,我描述了性能和实体框架太慢了。 (我的应用程序在大约1.2秒内处理2条消息,其中我正在重写的(传统)应用程序同时执行5-6条消息。(旧应用程序调用sprocs进行数据库访问。)
我的分析指向实体框架占用每条消息的大部分时间。
那么,我的选择是什么?
那里有更好的ORM吗? (只支持正常读取和写入对象的东西,并且速度快......)
有没有办法让实体框架更快?
(注意:当我说得更快时,我的意思是长期运行,而不是第一次通话。(第一次通话很慢(消息为15秒),但这不是问题。我只是需要对于其余的消息来说速度很快。)
一些神秘的第三选项可以帮助我提高服务速度。
注意:我的大部分数据库互动都是创建和更新。我很少选择和删除。
答案 0 :(得分:65)
事实上,实体框架等产品总是缓慢而低效,因为他们正在执行更多的代码。
我也觉得很愚蠢,人们建议应该优化LINQ查询,查看生成的SQL,使用调试器,预编译,采取许多额外步骤等,即浪费大量时间。没有人说 - 简化!每个人都希望通过采取更多步骤(浪费时间)来进一步复杂化。
常识方法根本不是使用EF或LINQ。使用纯SQL。没有什么问题。仅仅因为程序员之间存在群体心态,并且他们觉得在那里使用每一种新产品的冲动并不意味着它是好的或者它会起作用。大多数程序员认为,如果他们合并了一家大公司发布的每一条新代码,那么它就会让他们成为一个更聪明的程序员;根本不是真的。智能编程主要是关于如何以更少的麻烦,不确定性以及在最短的时间内完成更多工作。记住 - 时间!这是最重要的元素,所以试着想方设法不要浪费它来解决坏/臃肿代码中的问题,只是为了符合一些奇怪的所谓'模式'
放松,享受生活,从编码中休息一下,停止使用额外的功能,代码,产品和“模式”。生命是短暂的,你的代码的生命甚至更短,它肯定不是火箭科学。删除LINQ,EF等层,你的代码将高效运行,可以扩展,是的,它仍然很容易维护。过多的抽象是一种糟糕的“模式”。
这就是解决问题的方法。
答案 1 :(得分:44)
您应该首先分析实体框架实际发布的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 });
}
可以替换为:
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 });
}
我只是输入了我的头脑,所以这不完全是如何执行的,但是如果你告诉它你对查询所知的一切,EF实际上做了一些很好的优化(在这种情况下,我们需要类别名称)。但这不像是预先加载(db.Products.Include(“Categories”)),因为投影可以进一步减少要加载的数据量。
答案 2 :(得分:35)
一个建议是仅对单记录CRUD语句使用LINQ to Entity Framework。
对于更多参与的查询,搜索,报告等,编写存储过程并按照on MSDN所述将其添加到Entity Framework模型。
这是我与我的几个网站采用的方法,它似乎是生产力和性能之间的良好折衷。实体框架并不总是为手头的任务生成最有效的SQL。而不是花时间弄清楚原因,为更复杂的查询编写存储过程实际上为我节省了时间。一旦熟悉了该过程,将存储过程添加到EF模型中并不是一件容易的事。当然,将它添加到模型中的好处是,您可以获得使用ORM所带来的所有强类型的优点。
答案 3 :(得分:14)
如果您纯粹获取数据,那么当您告诉EF不跟踪它所获取的实体时,它对性能有很大帮助。通过使用MergeOption.NoTracking来完成此操作。 EF将生成查询,执行它并将结果反序列化为对象,但不会尝试跟踪实体更改或任何此类性质。如果查询很简单(没有花太多时间等待数据库返回),我发现将其设置为NoTracking可以使查询性能提高一倍。
请参阅MergeOption枚举中的这篇MSDN文章:
Identity Resolution, State Management, and Change Tracking
这似乎是一篇关于EF表现的好文章:
答案 4 :(得分:6)
您说您已对该应用程序进行了分析。你有没有对ORM进行过分析?有一个来自Ayende的EF分析器,它将突出显示您可以优化EF代码的位置。你可以在这里找到它:
请记住,如果您需要获得性能,可以在ORM旁边使用传统的SQL方法。
如果有更快/更好的ORM?根据您的对象/数据模型,您可以考虑使用其中一个微型ORM,例如Dapper,Massive或PetaPoco。
Dapper网站发布了一些比较基准,可以让您了解它们与其他ORM的比较。但值得注意的是,微型ORM不支持EF和NH等完整ORM的丰富功能集。
您可能需要查看RavenDB。这是一个非关系型数据库(再次来自Ayende),它允许您直接存储POCO,而不是mapping needed。 RavenDB针对读取进行了优化,通过消除操作模式和将对象映射到该模式的需要,使开发人员的工作变得更加轻松。但是,请注意这是使用ORM方法的一种截然不同的方法,这些方法在product's site中列出。
答案 5 :(得分:3)
我发现@Slauma here的答案对于加快速度非常有用。我对插入和更新使用了相同的模式 - 并且性能飙升。
答案 6 :(得分:2)
根据我的经验,问题不是EF,而是ORM方法本身。
通常,所有ORM都会遇到N+1问题而不是优化的查询等。我最好的猜测是追踪导致性能下降的查询并尝试调整ORM工具,或者用SPROC重写这些部分。
答案 7 :(得分:1)
这是一个简单的非框架,非ORM选项,以10,000个/秒的速度加载30个字段左右。在旧笔记本电脑上运行,可能比在真实环境中更快。
https://sourceforge.net/projects/dopersistence/?source=directory
答案 8 :(得分:1)
我也遇到了这个问题。我讨厌转储EF,因为它工作得很好,但它只是很慢。在大多数情况下,我只想找到一条记录或更新/插入。即使是这样简单的操作也很慢。我将一张表中的1100条记录拉回到一个列表中,该操作需要花费6秒时间。对我来说这太长了,即使节省也需要太长时间。
我最终制作了自己的ORM。我从数据库中提取了相同的1100条记录,我的ORM耗时2秒,比EF快得多。我的ORM的一切几乎都是即时的。现在唯一的限制是它只适用于MS SQL Server,但可以更改为与Oracle等其他人一起使用。我现在就使用MS SQL Server。
如果您想尝试我的ORM,请点击链接和网站:
https://github.com/jdemeuse1204/OR-M-Data-Entities
或者如果你想使用金块:
PM&GT;安装包OR-M_DataEntities
文档也在那里
答案 9 :(得分:0)
在您分析后进行优化才有意义。如果您发现数据库访问速度很慢,则可以转换为使用存储过程并保留EF。如果您发现EF本身很慢,您可能必须切换到不同的ORM或根本不使用ORM。
答案 10 :(得分:0)
我们有一个类似的应用程序(Wcf - &gt; EF - &gt;数据库),每秒可以轻松执行120个请求,因此我更确定EF不是您的问题,可以说,我看到了主要的性能编译查询的改进。
答案 11 :(得分:0)
我使用EF,LINQ to SQL和dapper。小巧玲珑是最快的。 示例:我需要1000个主记录,每个记录包含4个子记录。我用LINQ来sql,花了大约6秒钟。然后我切换到dapper,从单个存储过程中检索了2个记录集,并为每个记录添加了子记录。总时间1秒。
此外,存储过程使用了表值函数和交叉应用,我发现标量值函数非常慢。
我的建议是使用EF或LINQ to SQL,并在某些情况下切换到精巧。
答案 12 :(得分:-1)
实体框架本身不应造成重大瓶颈。可能还有其他原因。您可以尝试将EF切换到Linq2SQL,两者都具有比较功能,并且代码应该易于转换,但在许多情况下,Linq2SQL比EF更快。