2016-07-22 3 views
5

Я изучал перенос некоторых наших EF6-кода на Dapper для повышения производительности, когда у меня возникла странная проблема. Запрос одной строки принимал почти в 10 раз столько же в 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 для 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(); 
Смежные вопросы