2016-07-22 312 views
5

我在研究将一些EF6代码移植到Dapper中,以便在遇到奇怪问题时获得更好的性能。单行查询在Dapper中的数量比在EF中的差不多是。它是这样的:糟糕的Dapper性能参数化查询

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

我考虑到,第一查询可能会很慢,所以我把测量值的“热身”的时期。我认为这可能是重用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一个速度更快。

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

+1

简介生成的SQL – stuartd

+0

我有各种各样的使用,因为缺乏自然键与EF意见的问题。我不确定你的视图是什么(也许你在EF中不能像使用CTE那样做),但为什么不在视图中尝试查询而不是使用Dapper查看视图。 – juharr

+1

你如何进行基准测试? – mxmissile

回答

0

它与参数的数据类型有关。如果它与索引不匹配,那么它会投射每一行来比较它。将它作为字符串进行处理,然后由sql解析器进行选择。

0

根据您的最终示例,您的列最有可能是varchar,但是当您使用参数化查询时,参数将以nvarchar发送。由于nvarchar to 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();