Dapper的QueryFirstorDeFault方法真的很慢吗?
我读到Dapper比EF快(至少在检索数据时)要快,我想确认这一点,因此我在BenchmarkDotnet的帮助下比较了Dapper和EntityFramework。
所以我尝试了这个...
[Benchmark]
public Player EntityFramework_GetByName()
{
using (ApplicationDbContext context = new())
{
return context.Players.FirstOrDefault(x => x.FirstName == _name);
}
}
[Benchmark]
public Player Dapper_GetByName()
{
using (SqlConnection conn = new(Database.ConnectionString))
{
return conn.QueryFirstOrDefault<Player>($"SELECT * FROM Players WHERE FirstName = '{_name}'");
}
}
但是结果不是我的期望...
然后我阅读在这里关于列类型“问题”,以及如何影响性能,因此我将列的类型更改为NVarchar,最大长度为100,而我的代码为dapper为此,
[Benchmark]
public Player Dapper_GetByName()
{
using (SqlConnection conn = new(Database.ConnectionString))
{
return conn.QueryFirstOrDefault<Player>($"SELECT * FROM Players WHERE FirstName = @name", new
{ @name = new DbString { Value = _name, IsAnsi = false } });
}
}
基准测试的结果如下..
方法 | 平均 | 误差 | STDDEV | 分配的 |
---|---|---|---|---|
Dapper_getByName | 41,092.8 US | 1,400.39 US | 4,085.0 US US | 4 KB |
ENTITYFRAMEWORKWORK_GETBYWORKERWORK_GETBYNAME | 2,971.6 US | 305.43 US 305.43 US | 895.8 US 110 KB US | 110 KB |
。有没有办法改善这一点?
I read that Dapper is faster than EF (at least at retrieving data) and I want to confirm that so I am comparing Dapper and EntityFramework with the help of BenchmarkDotNet.
So I tried this...
[Benchmark]
public Player EntityFramework_GetByName()
{
using (ApplicationDbContext context = new())
{
return context.Players.FirstOrDefault(x => x.FirstName == _name);
}
}
[Benchmark]
public Player Dapper_GetByName()
{
using (SqlConnection conn = new(Database.ConnectionString))
{
return conn.QueryFirstOrDefault<Player>(quot;SELECT * FROM Players WHERE FirstName = '{_name}'");
}
}
But the result are not what I expecting...
Then I read here about the column type "problem" and how that can affect the performance, so I change the type of the column to NVarchar with max length of 100 and my code for the Dapper to this
[Benchmark]
public Player Dapper_GetByName()
{
using (SqlConnection conn = new(Database.ConnectionString))
{
return conn.QueryFirstOrDefault<Player>(quot;SELECT * FROM Players WHERE FirstName = @name", new
{ @name = new DbString { Value = _name, IsAnsi = false } });
}
}
The results of the benchmark tests are the following..
Method | Mean | Error | StdDev | Allocated |
---|---|---|---|---|
Dapper_GetByName | 41,092.8 us | 1,400.39 us | 4,085.0 us | 4 KB |
EntityFramework_GetByName | 2,971.6 us | 305.43 us | 895.8 us | 110 KB |
The difference is very big. Is there a way to improve this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为这个例子非常清楚地展示了直接使用 Dapper、CA.Blocks.DataAccess 或 ADO.NET 时 SQL 查询生成的责任。当使用这些包访问数据库时,开发人员完全负责 SQL 查询、其投影和执行。使用 EF 时,生成查询的责任不再由开发人员承担,而是委托给 EF。这是一把双刃剑,可能会产生良好的查询,也可能会产生非常糟糕的查询。 Dapper 中的大部分性能提升都来自于对 SQL 的完全控制和消除不良 SQL 的生成。反之亦然,与 EF 相比,Dapper 的大多数性能问题都是由于 EF 创建了更好的查询。
那么这里发生了什么。简单来说,EF 已经查看了请求,并知道您只知道第一条记录 FirstOrDefault,因此它的查询生成导致
您正在进行比较的 Dapper 查询是,
所以我怀疑差异纯粹在于 SQL。使用的Test数据库,可能在Person表中有很多记录。给定这些数字,名称上可能没有索引,从而导致表扫描以查找匹配的数据。
在 EF 生成的查询中,数据库可以在找到第一条记录后立即停止执行,在 Dapper 示例中,数据库根据名称组装包含所有匹配项的完整记录集,然后发送该行集。 Dapper 只是读取第一行并关闭连接。
为了进行公平的比较,您需要将查询更改为 top 1。
同样,决定使用 Dapper 来提高性能意味着您需要了解并喜欢 SQL。
I think this example shows very clearly the responsibility of SQL query generation when using Dapper, CA.Blocks.DataAccess or ADO.NET directly. When using these packages for accessing the database the developer is entirely in charge of the SQL query, its projection and execution. When using EF the responsibility of generating the query is removed from the developer and delegated to EF. This is a double-edged sword and can result in good queries as well as very bad queries. Most of the performance gains made in Dapper are from having full control over the SQL and eliminating bad SQL generation. The converse is also true, most of the performance problems with Dapper when compared to EF are due to EF creating a better query.
So what is happening here. In simple terms EF has looked at the request and has knowledge that you only what the first record FirstOrDefault so its query generation has resulted in
The Dapper query you are making the comparison with is
So the difference I suspect is purely on SQL. The Test database used, probably has many records in the Person table. Given the numbers it is likely that there is no index on name resulting in a Table Scan to find the matching data.
In the query generated by EF the database can stop the execute as soon as it finds the first record, in the Dapper example the database assembles the full record set with all the matches based on name then sends that row-set. Dapper is simply reading the first row and closing the connection.
To make this a fair comparison you need to change the query to be top 1. Like
Also, the decision to go with Dapper for performance means you need to get to know and love SQL.
嗯,也许你不应该
与基准:
只比较内部部分
Uhm, maybe you should not compare
vs
Benchmark only the inner part: