2016-07-22 313 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();