为啥实体框架在直接选择语句中的执行速度比 Dapper 快 [关闭]

Posted

技术标签:

【中文标题】为啥实体框架在直接选择语句中的执行速度比 Dapper 快 [关闭]【英文标题】:Why Entity Framework performs faster than Dapper in direct select statement [closed]为什么实体框架在直接选择语句中的执行速度比 Dapper 快 [关闭] 【发布时间】:2017-04-23 10:06:56 【问题描述】:

我是使用 ORM 处理数据库的新手,目前我正在制作一个新项目,我必须决定是否使用实体框架或 Dapper。我读过很多文章说 Dapper 比 Entity Framework 快。

所以我做了 2 个简单的原型项目,一个使用 Dapper,另一个使用 Entity Framework 和一个函数来从一张表中获取所有行。 表架构如下图

两个项目的代码如下

用于 Dapper 项目

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
IEnumerable<Emp> emplist = cn.Query<Emp>(@"Select * From Employees");
sw.Stop();
MessageBox.Show(sw.ElapsedMilliseconds.ToString());

对于实体框架项目

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
IEnumerable<Employee> emplist = hrctx.Employees.ToList();
sw.Stop();
MessageBox.Show(sw.ElapsedMilliseconds.ToString());

仅在我第一次运行项目时多次尝试上述代码后,dapper 代码会更快,并且在第一次之后,我总是从实体框架项目中获得更好的结果 我还在实体框架项目上尝试了以下语句来停止延迟加载

hrctx.Configuration.LazyLoadingEnabled = false;

但除第一次外,相同的 EF 执行速度更快。

任何人都可以给我解释或指导是什么让 EF 在这个示例中更快,尽管网络上的所有文章都说相反

更新

我已将实体示例中的代码行更改为

IEnumerable<Employee> emplist = hrctx.Employees.AsNoTracking().ToList();

使用某些文章中提到的 AsNoTracking 会停止实体框架缓存,并且在停止缓存后,dapper 示例的性能会更好,(但差别不大)

【问题讨论】:

这不是一个基准测试...您只是在测试一个 非常 基本场景,其中 EF 恰好更快,因为它没有很多事情要做。在实际场景中,您可能会发现 Dapper 更快(因为它只做一件事:将查询结果映射到对象),但您必须编写更多代码来做同样的事情。 您应该尝试真实场景,包括连接、过滤器、分组、更新、插入等 当您使用几个连接进行查询时,您将开始注意到巨大的性能差异,一旦 ef 需要编译您的查询,您将获得性能影响 我很久以前做了一些测试,发现 EF 在返回少量行时始终更快。我仍然不确定为什么会这样,但我猜我认为 EF 可能会在默认设置上做更好的连接管理。在映射方面,我认为 EF 和 dapper 之间没有显着的性能差异,但是,如果您想要对查询进行边缘性能调整,那么您无法使用 LINQ ORM 做一些事情。我的(旧)文章在这里:blog.staticvoid.co.nz/2012/3/24/… 这种测试没用。您应该测试很多操作(所有 CRUD)并使用真正的 ORM,而不是 dapper。 Linq2db 有一些精巧的高级功能,甚至 EF 都做不到,并且可以与 Linq 一起使用,因此运行基准测试是一个更好的选择。 【参考方案1】:

ORM(对象关系映射器)是一种在应用程序和数据源之间创建层并返回关系对象而不是返回的工具 (就您正在使用的 c# 而言)ADO.NET 对象。这是每个 ORM 都会做的基本事情。

为此,ORM 通常会执行查询并将返回的DataReader映射 到 POCO 类。 Dapper 仅限于此。

为了进一步扩展这一点,一些 ORM(也称为“完整 ORM”)会做更多的事情,例如为您生成查询以使您的应用程序数据库独立,缓存您的数据以供将来调用,为您管理工作单元等等.所有这些都是很好的工具,为 ORM 增加了价值;但它伴随着成本。实体框架属于此类。

要生成查询,EF 必须执行附加代码。缓存提高了性能,但管理缓存需要执行额外的代码。 EF 提供的工作单元和任何其他附加功能也是如此。所有这一切都为节省了编写额外代码的时间,而 EF 支付了成本。

成本就是性能。由于 Dapper 做的是非常基础的工作,所以它更快;但是您必须编写更多代码。由于 EF 做的远不止这些,它(有点)慢;但你必须编写更少的代码。

那么为什么您的测试显示相反的结果? 因为你正在执行的测试没有可比性。

如上所述,完整的 ORM 具有许多好的特性;其中之一是 UnitOfWork。跟踪是 UoW 的职责之一。当对象第一次被请求(SQL 查询)时,它会导致到数据库的往返。然后将该对象保存在内存缓存中。完整的 ORM 跟踪对此已加载对象所做的更改。如果再次请求相同的对象(包括已加载对象的同一 UoW 范围内的其他 SQL 查询),它们不会执行数据库往返。相反,它们从内存缓存中返回对象。这样可以节省大量时间。 Dapper 不支持此功能,这会导致它在您的测试中执行较慢。

但是,此优势仅适用于多次加载相同对象的情况。此外,如果加载到内存中的对象数量过多,则会降低整个 ORM 的速度,因为检查内存中的对象所需的时间会更长。同样,这种好处取决于用例。

【讨论】:

在编写复杂查询时,在某些情况下 EF 不会生成最佳 SQL,无论如何您都必须手动执行。所以我不会说 EF 真的很“完整”,它只是对非常简单的查询有帮助,但你必须彻底了解它才能有效地使用它,你也必须彻底了解 SQL,因此,你必须了解 2 大当你刚开始阅读一本关于 EF 的书时,它看起来非常简单和有希望,而不是预期的 1。但是日复一日,您一次又一次地面临新的挑战。 其中一些是通过棘手的 LINQ 解决的,而有些则仅使用纯 SQL 解决。您花费大量时间来了解您可以使用 EF 做什么以及不能做什么。项目的工作量越大,LINQ 查询就越显示出它们的低效率,你也必须用纯 SQL 重写它们。然后你意识到你必须关闭它的默认自动跟踪器并使用一些第三方库,比如 EntityFramework-Plus 来让它更快地工作。最后你认为发生了什么?为什么我选择了这个完整的 ORM 并花了很多时间来学习它,而现在我只将它用于简单的查询?!然后你会找到 Dapper。 @Sergey:同意;但也很少有其他方面需要考虑。请阅读this博客。 @Sergey: "And then you find Dapper." 不错的选择。恕我直言,在某些情况下,全 ORM、微 ORM 和手写查询发挥了它们的作用并具有它们的重要性。设计决定使用什么以及我们应该从中得到什么。 我已经阅读了这篇文章。我并没有轻蔑地谈论 ORM。相反,我认为人们付出了很大的努力来让它以最好的方式工作,而且它现在真的很有效。我真正的意思是你必须同时学习 SQL 和 ORM。 Martin F. 也说了同样的话,甚至更多——你必须先学习 SQL。我想说的是,对于刚开始通过 EF 使用 DB 的初学者,每本书和每篇文章都应该以大字体警告这一点。但事实并非如此,因此,新手会像我一样陷入误解和错误的期望中。【参考方案2】:

I read many articles which says that Dapper is faster than Entity Framework

互联网上大多数基准测试的问题在于他们将 EF Linq 与 Dapper 进行比较。这也是你所做的。这是不公平的。自动生成的查询 (EF) 通常不等于优秀开发人员编写的查询。

这个,

IEnumerable<Employee> emplist = hrctx.Employees.ToList();

应该换成这个。

IEnumerable<Employee> emplist = hrctx.Employees.FromSql(@"Select * From Employees").AsNoTracking();

编辑:

正如@mjwills 所指出的,下面是insertupdateselect 语句的结果表。

Dapper 的性能优于 EF Core 2。但是,可以看出,对于 EF 普通查询,差异非常小。我已经发布了complete details here。

【讨论】:

EF Linq to Dapper 是最准确的比较。您知道有多少开发人员在使用 EF 时会手工制作查询? Ef Linq to Dapper 是基于使用情况的苹果对苹果的比较。【参考方案3】:

Entity Framework Core 2.0 vs. Dapper performance benchmark, querying SQL Azure tables 的文章证实了 Dapper 有点快,但不足以忽略“完全 ORM”的好处。

【讨论】:

那篇文章做了很多错误的假设,与现实的测试用例相去甚远。查看this reddit thread 了解更多信息。 @Alternatex,感谢您的链接。但结论是一样的:Dapper 的性能只是稍微好一点,但 EF 的功能要多得多。【参考方案4】:

将它们混合在一起没有问题。在我当前的项目中,我使用 Dapper 来选择数据,使用 EF 来创建和更新以及数据库迁移。

当涉及到涉及两个以上表或存在一些复杂操作(由多个列连接、使用 >= 和

【讨论】:

最后一句话不适用于 EF-core 当前版本:2.1.1。另外,FWIW,我也不同意第二段的开头。在 LINQ 中编写复杂的查询比在 SQL 中容易得多,尤其是。使用导航属性时。最后,这并不能真正回答为什么 EF 在这种特定情况下更快的问题。 @GertArnold 我找不到在没有 DbSet ***.com/questions/45698359/… 的情况下映射原始 SQL 查询的方法。我你知道怎么做,请问你在哪里可以找到如何做到这一点?至于什么更容易使用,这是一个品味问题。以我的经验,原始 SQL 更灵活。对我来说。 不完全是FromSq,而是:docs.microsoft.com/en-us/ef/core/modeling/query-types

以上是关于为啥实体框架在直接选择语句中的执行速度比 Dapper 快 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

存储过程和实体框架的性能

mysql数据库: 为啥sql语句在查询分析中的执行速度远远快于在应用程序的(而且有时候后者慢的很多)

为啥实体框架不能在 LINQ 语句中使用 ToString()?

如果删除 AsNoTraking,速度会更快 - 为啥? - 实体框架 5.0 - SQL Server 2008 R2

为啥选择 JMS 作为异步解决方案?为啥它比简单的实体 bean 更好?

大量数据多表联合查询时时, 使用视图,是否比直接查询速度要快! 有高手请给讲讲,如何提高查询速度