当我遇到一个奇怪的问题时,我正在研究将一些EF6代码移植到Dapper以获得更好的性能。单行查询在Dapper中的亮度几乎是其中的10倍。它看起来像这样:
using (IDbConnection conn = new SqlConnection("connection string"))
{
row = conn.Query<ReportView>("select * from ReportView where ID = @ID",
new {ID = id}))
.FirstOrDefault();
}
此查询以大约80列为目标,EF版本使用相同的查询和相同的模型。作为参考,这是EF版本:
row = context.ReportViews.Where(s => s.ID == id).FirstOrDefault();
我考虑到第一个查询可能很慢,所以我在'#34;热身后'进行了测量。期。我认为重用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();
}
此查询实际上比EF更快。
那么这里发生了什么?为什么参数化查询要慢得多?
答案 0 :(得分:5)
根据您的最后一个示例,您的列似乎很可能是varchar
,但是当您使用参数化查询时,参数将作为nvarchar
发送。由于nvarchar到varchar可能涉及数据丢失,因此SQL会将表中的每个值转换为nvarchar以进行比较。可以想象,转换每一行进行比较的速度很慢,并且无法使用索引。
要解决此问题,您有两种选择:
如果您的数据库根本没有使用nvarchar,您只需在应用程序启动期间更改映射:
Dapper.SqlMapper.AddTypeMap(typeof(string), System.Data.DbType.AnsiString);
否则您可以按查询更改它:
row = conn.Query<ReportView>("select * from ReportView where ID = @ID",
new {ID = new DbString { Value = id, IsAnsi = true }})
.FirstOrDefault();
答案 1 :(得分:0)
它与参数的数据类型有关。如果它与索引的那个不匹配,那么它会转换每一行来比较它。以字符串形式执行,sql解析器选择类型。