我是使用 ORM 处理数据库的新手,目前我正在制作一个新项目,我必须决定是使用 Entity Framework 还是 Dapper。我读了很多文章,都说 Dapper 比实体框架更快。
因此,我制作了 2 个简单的原型项目,一个使用 Dapper,另一个使用实体框架和一个函数来从一张表中获取所有行。 表架构如下图
两个项目的代码如下
对于 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());
在多次尝试上述代码后,仅在第一次运行该项目时,简洁的代码会更快,并且在第一次之后,我总是从实体框架项目中获得更好的结果 我还在实体框架项目上尝试了以下语句来停止延迟加载
hrctx.Configuration.LazyLoadingEnabled = false;
但除了第一次之外,相同的 EF 仍然执行得更快。
任何人都可以给我解释或指导,说明是什么让 EF 在此示例中更快,尽管网络上的所有文章都说相反的情况
更新
我已将实体示例中的代码行更改为
IEnumerable<Employee> emplist = hrctx.Employees.AsNoTracking().ToList();
使用某些文章中提到的 AsNoTracking 会停止实体框架缓存,停止缓存后,dapper 示例的性能会更好,(但差别不是很大)
ORM(对象关系映射器)是一种在应用程序和数据源之间创建层并返回关系对象而不是对象的工具 (就您正在使用的 C# 而言)ADO.NET 对象。这是每个 ORM 都会做的基本事情。
为此,ORM 通常会执行查询并将返回的 DataReader
映射到 POCO 类。 Dapper 仅限于此。
为了进一步扩展这一点,一些 ORM(也称为“完整 ORM”)可以做更多的事情,例如为您生成查询以使您的应用程序数据库独立、缓存您的数据以供将来调用、为您管理工作单元等等。所有这些都是很好的工具,为 ORM 增加了价值;但这是有代价的。实体框架属于此类。
为了生成查询,EF 必须执行额外的代码。缓存提高了性能,但管理缓存需要执行额外的代码。对于工作单元和 EF 提供的任何其他附加功能也是如此。所有这些都节省了
您编写额外的代码,并且 EF 支付费用。 而
成本就是性能。由于 Dapper 做了非常基本的工作,所以速度更快;但你必须编写更多代码。由于 EF 的作用远不止于此,因此它(有点)慢;但你必须编写更少的代码。
那么为什么你的测试显示相反的结果?
因为您正在执行的测试没有可比性。
如上所述,完整的 ORM 有许多好的特性;其中之一是UnitOfWork。跟踪是 UoW 的职责之一。当第一次请求该对象(SQL 查询)时,会导致与数据库的往返。然后该对象被保存在内存缓存中。完整的 ORM 会跟踪对此已加载的对象所做的更改。如果再次请求相同的对象(同一 UoW 范围内包含已加载对象的其他 SQL 查询),它们不会进行数据库往返。相反,它们从内存缓存中返回对象。这样可以节省大量时间。
但是,此优势仅适用于多次加载相同对象的情况。此外,如果内存中加载的对象数量太多,这会减慢整个 ORM 的速度,因为“检查”内存中的对象所需的时间会更长。同样,这种好处取决于用例。
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 所指出的,下面是 insert
、
update
和
select
语句的结果表。Dapper 的性能优于 EF Core 2。但是,可以看出,对于 EF 普通查询,差异非常小。我已在此发布完整详细信息。