为什么实体框架在直接选择语句中的执行速度比Dapper快

时间:2017-04-23 10:06:57

标签: c# entity-framework dapper

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

所以我使用Dapper创建了两个简单的原型项目,另一个使用Entity Framework和一个函数从一个表中获取所有行。 表模式如下图

Table Schema

以及两个项目的代码如下

用于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());

for Entity Framework Project

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示例的效果会更好,(但差别不是很大)

4 个答案:

答案 0 :(得分:29)

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

为此,ORM通常执行查询并将映射返回的DataReader执行到POCO类。 Dapper在这里有限。

为了进一步扩展这一点,一些ORM(也称为#34;完整的ORM和#34;)做更多的事情,比如为您创建查询以使您的应用程序数据库独立,缓存数据以备将来调用,管理工作单元为了你和更多。所有这些都是很好的工具,为ORM增添了价值;但它带有成本。实体框架属于这一类。

要生成查询,EF必须执行其他代码。缓存可提高性能,但管理缓存需要执行其他代码。对于工作单元和EF提供的任何其他附加功能也是如此。所有这些都可以节省编写额外的代码,EF支付费用。

成本是性能。由于Dapper做了非常基本的工作,它更快;但你必须写更多的代码。由于EF做的远远不止于此,它会慢一点;但你必须少写代码。

那么为什么你的测试显示相反的结果?
因为您正在执行的测试无法比较。

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

但是,此优势仅适用于多次加载相同对象的情况。此外,如果内存中加​​载的对象数太多,这将减慢完整的ORM,因为检查内存中的对象所需的时间将更长。同样,这种好处取决于用例。

答案 1 :(得分:2)

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

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

这个

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

应替换为此。

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

编辑:

@mjwills指出,以下是insertupdateselect语句的结果表。

enter image description here

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

当涉及到多个表或涉及一些复杂操作(通过多个列联接,使用> =和<=子句联接,递归选择,CTE等)的复杂查询时,Dapper极为有用。在哪里使用纯SQL比LINQ容易得多。据我所知,实体框架(与Dapper不同)不能在自定义DTO上使用.FromSql()方法。它只能映射应该在数据库上下文中的一个表。

相关问题