参数化查询的Bad Dapper性能

Sys*_*own 7 c# performance entity-framework dapper

当我遇到一个奇怪的问题时,我正在研究将一些EF6代码移植到Dapper以获得更好的性能.单行查询在Dapper中的使用率几乎是EF中的10倍.它看起来像这样:

using (IDbConnection conn = new SqlConnection("connection string"))
{                
      row = conn.Query<ReportView>("select * from ReportView where ID = @ID", 
                                          new {ID = id}))
                                  .FirstOrDefault();
}
Run Code Online (Sandbox Code Playgroud)

此查询以大约80列为目标,EF版本使用相同的查询和相同的模型.作为参考,这是EF版本:

row = context.ReportViews.Where(s => s.ID == id).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

我考虑到第一个查询可能很慢,所以我在"预热"期后进行了测量.我认为重用EF模型可能是一个问题,所以我创建了一个简单的POCO作为模型.这些都没有效果.所以我玩了它,尝试不同的东西,并决定尝试使用SQL注入的连接SQL语句.

using (IDbConnection conn = new SqlConnection("connection string"))
{                
      row = conn.Query<ReportView>(string.Format("select * from ReportView where ID = '{0}'", 
            id)).FirstOrDefault();
}
Run Code Online (Sandbox Code Playgroud)

这个查询实际上比EF更快.

那么这里发生了什么?为什么参数化查询这么慢?

Ric*_*lay 6

根据您的最后一个示例,您的列似乎很可能是,varchar但是当您使用参数化查询时,参数将被发送为nvarchar.由于nvarchar到varchar可能涉及数据丢失,因此SQL会将表中的每个值转换为nvarchar以进行比较.可以想象,转换每一行进行比较的速度很慢,并且会阻止使用索引.

要解决这个问题,您有两种选择:

如果您的数据库根本不使用nvarchar,则只需在应用程序启动期间更改映射:

Dapper.SqlMapper.AddTypeMap(typeof(string), System.Data.DbType.AnsiString);
Run Code Online (Sandbox Code Playgroud)

否则,您可以按查询更改它:

row = conn.Query<ReportView>("select * from ReportView where ID = @ID", 
                              new {ID = new DbString { Value = id, IsAnsi = true }})
                              .FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)