Entity Framework Vs Сохраненные процедуры - оценка эффективности
Я пытаюсь установить, насколько медленнее Entity Framework находится над хранимыми процедурами. Я надеюсь убедить своего босса позволить нам использовать Entity Framework для простоты разработки.
Проблема заключается в том, что я провел тест производительности, и похоже, что EF примерно в 7 раз медленнее, чем хранимые процедуры. Мне очень трудно поверить, и мне интересно, не хватает ли я чего-то. Это убедительный тест? Есть ли что-то, что я могу сделать, чтобы повысить производительность теста EF?
var queries = 10000;
// Stored Proc Test
Stopwatch spStopwatch = new Stopwatch();
spStopwatch.Start();
for (int i = 0; i < queries; i++ )
{
using (var sqlConn = new SlxDbConnection().Connection)
{
var cmd = new SqlCommand("uspSearchPerformanceTest", sqlConn) { CommandType = CommandType.StoredProcedure };
cmd.Parameters.AddWithValue("@searchText", "gstrader");
sqlConn.Open();
SqlDataReader dr = cmd.ExecuteReader();
List<User> users = new List<User>();
while (dr.Read())
{
users.Add(new User
{
IsAnonymous = Convert.ToBoolean(dr["IsAnonymous"]),
LastActivityDate = Convert.ToDateTime(dr["LastActivityDate"]),
LoweredUserName = dr["LoweredUserName"].ToString(),
MobileAlias = dr["MobileAlias"].ToString(),
UserId = new Guid(dr["UserId"].ToString()),
UserName = (dr["UserName"]).ToString()
});
}
var username = users.First().UserName;
sqlConn.Close();
}
}
spStopwatch.Stop();
Console.WriteLine("SP - {0} Queries took {1}", queries, spStopwatch.ElapsedMilliseconds );
// EF Test
Stopwatch entityStopWatch = new Stopwatch();
var context = new SlxDbContext();
var userSet = context.Set<User>();
entityStopWatch.Start();
for (int i = 0; i < queries; i++)
{
User user = userSet.Where(x => x.UserName == "gstrader").First();
}
entityStopWatch.Stop();
Console.WriteLine("Entity - {0} Queries took {1}", queries, entityStopWatch.ElapsedMilliseconds);
Результат:
SP - 10000 запросов заняло 2278
Entity - 10000 запросов заняло 16277
Ответы
Ответ 1
Есть несколько вещей, которые вы можете сделать для оптимизации вашего запроса. Здесь, в MSDN, вы можете найти хороший обзор.
Но, честно говоря, хранимая процедура с ручным сопоставлением всегда будет быстрее в производительности. Но спросите себя, насколько важна производительность? В большинстве проектов время разработки более важно, чем производительность. Что было труднее развивать? Необработанный запрос с разбором или запрос Entity Framework?
ORM не разработаны, потому что они работают намного лучше, чем ручной подход. Мы используем их, потому что разработка намного проще!
Если вы пишете свое приложение с помощью Entity Framework и спрячете все ваши запросы за шаблоном репозитория, вы можете быстро развиваться, а затем, когда производительность становится проблемой, измерьте приложение, чтобы обнаружить узкое место. Тогда, возможно, некоторые из ваших запросов нуждаются в оптимизации и могут быть перемещены в хранимые процедуры и ручное сопоставление.
Ответ 2
В согласии с @Wouter de Kort...
Кроме того, когда вам нужно перейти к процедурам, вы можете использовать EF в сочетании с процедурами, помогающими перейти от одного к другому.
Переход к процедурам будет быстрее в типичном приложении, если вы объедините функциональность в хорошо разработанные процедуры. т.е. получите как можно больше работы в одном запросе sproc. Например, в приложении MVC для покупок, когда пользователь нажимает кнопку выписки, вы можете использовать ORM для чего-то вроде:
- найдите аутентификацию пользователя (это логин по-прежнему действителен?)
- найти разрешения (могут ли они купить указанные элементы?), есть ли особые требования?)
- найдите количество запасов, чтобы убедиться, что они не исчерпаны в процессе.
- напишите в БД, чтобы зарезервировать (удалить из доступных ресурсов) элементы перед оплатой.
- посмотреть информацию об оплате
- logging...?
Или это могут быть совершенно разные шаги, но в любом случае дело в том, что приложение MVC будет использовать ORM, чтобы сделать несколько вызовов в БД, чтобы перейти к следующему шагу.
Если вся эта логика инкапсулирована в один хорошо написанный sproc, тогда есть только один вызов sproc, и вы закончили. С помощью маршрута MVC-ORM данные должны быть скопированы из БД в драйвер и доставлены на ORM (обычно через сеть на другой хост), а затем прочитаны приложением MVC, чтобы сделать простое решение, а затем повторить до тех пор, пока все этапы не будут завершены, В случае использования sproc, который инкапсулирует этот этап выезда, происходит намного меньше копирования и перемещения данных, меньше сетевого ввода-вывода, меньше переключения контекста и т.д.
Подумайте о решении MVC-ORM таким образом. Лицо "А" хорошо осведомлено о фактах, а человек "В" имеет все сообразительность, чтобы принимать решения с данными фактами, которые он не представляет. Лицо "B" отправляет электронное письмо "А" для фактов. Основываясь на ответе от "А" , "Б" может потребовать еще несколько фактов, прежде чем принимать решение. Это много назад и вперед сообщений.
Если у вас есть один человек, который имеет все факты и знания для принятия решений, вам просто нужно задать один вопрос, и их мозг будет обрабатывать все внутренне, чтобы придумать ответ. Никакое обсуждение с другим человеком не связано. Естественно, это будет быстрее.
Это не значит, что это обязательно лучше. Разделение фактов из решения означает, что эти компоненты отдельно заменяются/проверяются, однако, если вы состоите в браке с вашим MVC и вашей БД, тогда это "не проблема".
С другой стороны, многие поклонники MVC ненавидят писать SQL, поэтому считают, что любая логика решения в SQL является стихийным бедствием. Для таких людей необходимо иметь любую логику, написанную на том же языке, что и MVC, потому что она ускоряет разработку для них. В некоторых случаях это также "не проблема", поскольку в случае некоторых RDMBS вы можете писать sprocs на том же языке, что и тот, который используется MVC (примеры:.Net-SQL Server sprocs могут быть записаны на С# и использовать .Net; Postgresql-функции (без sprocs) могут быть записаны в Perl, Python, PHP и др. Преимущество в этом случае заключается в том, что вы можете иметь быстрые sprocs, которые инкапсулируют несколько шагов в один вызов, и вы можете использовать язык программирования, который вы уже быстро кодируются.