Добрый день!
Подумываю над тем, чтобы опробовать какой-нибудь ORM в своем проекте. Реальной необходимости пока не вижу, прекрасно обхожусь запросами к БД, но может быть я слеп, надо изучить область
Так вот решил попробовать Entity Framework. На текущий момент приложению приходится выполнять довольно много мелких запросов (например, по первичному ключу), поэтому я решил проверить скорость выборки данных EF. Вот тестовый код, который сравнивает прямую выборку из БД через ADO.NET и через EF:
// ADO.NET
SqlConnection cnn = new SqlConnection ( @"Data Source=someserver;Initial Catalog=testdb;User ID=sa;Password=hh345;" );
cnn.Open ( );
SqlDataAdapter ad = new SqlDataAdapter ( "select * from hoteldictionary where HD_CNKEY = 1 AND HD_KEY = 232", cnn );
DateTime dtBegin = DateTime.Now;
for ( int i = 0; i < 100; i++ ) {
DataTable dt = new DataTable ( );
ad.Fill ( dt );
}
Console.WriteLine ( DateTime.Now.Subtract ( dtBegin ).TotalSeconds );
// EF
ctx.Connection.Open ( );
dtBegin = DateTime.Now;
for ( int i = 0; i < 100; i++ ) {
var hotels1 = ctx.HotelDictionary.Where ( h => h.HD_CNKEY == 1 && h.HD_KEY == 232 ).Select ( h=> new { h.HD_NAME } ).ToArray ( );
}
Console.WriteLine ( DateTime.Now.Subtract ( dtBegin ).TotalSeconds );
HD_KEY является первичным ключом в небольшой таблице на 2500 записей, так что каждая из выборок возвращает одну запись. Пример результатов запуска:
0,53125
1,171875
Проверял многократно, с разным количеством итераций, но все равно получается, что прямая выборка целой записи из БД в два раза быстрее, чем выборка одной колонки через EF. Если в обоих случаях выбирать одну колонку, то скорость будет больше в три раза. При этом EF генерит примерно такой же запрос, который написан вручную, так что разница во времени выполнения целиком из-за EF. Не особо верится, что копирование данных из результатов запроса в поля объекта занимает столько же, сколько работа сервера по выборке и возвращению данных. В связи с этим возникли вопросы:
1) Действительно разница такая большая, или я в эксперименте что-то упустил?
2) Если действительно скорость отличается заметно, то это проблема только в EF, или другие ORM такие же? Я видел тесты скорости EF vs NHibernate, и там EF побеждал, поэтому не думаю, что выбрал самый плохой продукт для замера скорости.
3) Были ли у кого-нибудь реальные проблемы с нагрузкой на сервер из-за ORMов вообще и EF в частности? Если бы мне не приходилось делать много мелких запросов к базе, я бы даже не задумывался над этим — удобство наверняка превысит небольшое падение производительности. Но мне приходится.
Здравствуйте, Степанов Андрей, Вы писали:
СА>1) Действительно разница такая большая, или я в эксперименте что-то упустил?
Да, разница большая. Где-то больше, где-то меньше.
СА>2) Если действительно скорость отличается заметно, то это проблема только в EF, или другие ORM такие же? Я видел тесты скорости EF vs NHibernate, и там EF побеждал, поэтому не думаю, что выбрал самый плохой продукт для замера скорости.
EF очень тормозной. BLToolkit, например, на порядок быстрее, но и концепция у него другая.
СА>3) Были ли у кого-нибудь реальные проблемы с нагрузкой на сервер из-за ORMов вообще и EF в частности? Если бы мне не приходилось делать много мелких запросов к базе, я бы даже не задумывался над этим — удобство наверняка превысит небольшое падение производительности. Но мне приходится.
Лично мой опыт убедил меня в том, что для большинства случаев ORM'ы не нужны вообще, от них больше проблем, чем пользы.
Каждый раз приходится смотреть:
как строится запрос и попадает ли он в эффективный индекс
какая часть запроса будет на сервере, а какая на клиенте
синхронизируется ли контекст ORM'а
и т.д. В общем, надо досконально знать возможности и кишки ORM, чтобы им безболезненно пользоваться.
В результате использую самую простую функциональность BLToolkit, где я сам контролирую запросы (т.е. BLToolkit просто устраняет небольшую рутину, которую постоянно приходится писать в ADO.NET).
Здравствуйте, Степанов Андрей, Вы писали:
СА>Проверял многократно, с разным количеством итераций, но все равно получается, что прямая выборка целой записи из БД в два раза быстрее, чем выборка одной колонки через EF. Если в обоих случаях выбирать одну колонку, то скорость будет больше в три раза. При этом EF генерит примерно такой же запрос, который написан вручную, так что разница во времени выполнения целиком из-за EF. Не особо верится, что копирование данных из результатов запроса в поля объекта занимает столько же, сколько работа сервера по выборке и возвращению данных. В связи с этим возникли вопросы: СА>1) Действительно разница такая большая, или я в эксперименте что-то упустил?
Конкретно для этого примера скорость можно слегка улучшить, если воспользваться Compiled Queries.
Здравствуйте, Степанов Андрей, Вы писали:
СА>Проверял многократно, с разным количеством итераций, но все равно получается, что прямая выборка целой записи из БД в два раза быстрее, чем выборка одной колонки через EF.
Кроме того, справедливости ради, в реальной более менее серьезной программе вы скорее всего будете использовать конкретные классы данных, а не обращение по индексу к таблице. Поэтому добавьте в тест скорости SQL варианта создание создание массива объектов и перенос туда данных из DataTable. Т.е. что выход обоих тестов был одинаковый по типу.
Здравствуйте, Степанов Андрей, Вы писали:
СА>Добрый день! СА>Подумываю над тем, чтобы опробовать какой-нибудь ORM в своем проекте. Реальной необходимости пока не вижу, прекрасно обхожусь запросами к БД, но может быть я слеп, надо изучить область
Здравствуйте, Степанов Андрей, Вы писали:
СА>2) Если действительно скорость отличается заметно, то это проблема только в EF, или другие ORM такие же? Я видел тесты скорости EF vs NHibernate, и там EF побеждал, поэтому не думаю, что выбрал самый плохой продукт для замера скорости. СА>3) Были ли у кого-нибудь реальные проблемы с нагрузкой на сервер из-за ORMов вообще и EF в частности?
Есть мнение, что идея ORM себя исчерпала.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, QrystaL, Вы писали:
IT>>Есть мнение, что идея ORM себя исчерпала. QL>А можно подробнее?
Идея жирных ORM — это представление модели данных приложения в виде виртуальной объектной БД, которая одновременно является объектной моделью приложения со встроенным свойством автоматической персистентности. Если посмотреть на современные фреймворки/паттерны потребители таких моделей данных (ASP.NET MVC и MVVM), то отчётливо видно, что в них отказываются от такого подхода. Модели строятся для каждого View, где модель данных используется лишь частично и то по принципу зачем писать два раза то, что уже один раз сгенерировано из схемы БД. Работа с самой БД организуется как с персистентным объектным хранилищем, а как простые функции загрузки и сохранения данных.
Т.е. практика показывает, что идея персистентности оказалось несостоятельной, а вместе с ней и идея жирных ORM.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, QrystaL, Вы писали:
IT>Работа с самой БД организуется как с персистентным объектным хранилищем, а как простые функции загрузки и сохранения данных.
"Я извиняюсь!..."(ц) А в чём отличие "персистентности" от "загрузки/сохранения"?
В целом, мысль поддерживаю: становиться "гуру" не пойми чего, да ещё написанного не пойми кем — ссыкотно, это вам не библиотечка JSON! Времени угрохаешь немало.
+100 к озвученному BLToolkit. И как у Elderos, у меня БЛТ "устраняет небольшую рутину": все запросы — руками, БЛТ мапит на объекты, работа с объектами, сохренение средствами БЛТ. Каждая строка кода полностью себя описывает.
Здравствуйте, Степанов Андрей, Вы писали:
СА>Проверял многократно, с разным количеством итераций, но все равно получается, что прямая выборка целой записи из БД в два раза быстрее, чем выборка одной колонки через EF. Если в обоих случаях выбирать одну колонку, то скорость будет больше в три раза. При этом EF генерит примерно такой же запрос, который написан вручную, так что разница во времени выполнения целиком из-за EF. Не особо верится, что копирование данных из результатов запроса в поля объекта занимает столько же, сколько работа сервера по выборке и возвращению данных. В связи с этим возникли вопросы: СА>1) Действительно разница такая большая, или я в эксперименте что-то упустил?
Упустил. Ты померил в цикле компиляцию лямбды. Это долгая операция, ускорить вполне можно с помощью компиляции запросов. http://msdn.microsoft.com/en-us/library/bb896297.aspx
Для простых запросов работает хорошо. Для сложных запросов, которые динамически строятся во время исполнения — не нужно.
СА>2) Если действительно скорость отличается заметно, то это проблема только в EF, или другие ORM такие же? Я видел тесты скорости EF vs NHibernate, и там EF побеждал, поэтому не думаю, что выбрал самый плохой продукт для замера скорости.
Все orm, поддерживающие Linq относительно долго компилируют запросы. Ef еще не самый худший вариант.
СА>3) Были ли у кого-нибудь реальные проблемы с нагрузкой на сервер из-за ORMов вообще и EF в частности? Если бы мне не приходилось делать много мелких запросов к базе, я бы даже не задумывался над этим — удобство наверняка превысит небольшое падение производительности. Но мне приходится.
Лучше прогони профайлером и посмотри какую часть компиляция лямбд занимает от общего времени работы.
То есть вместо синтетических тестов, сделай веб-приложение с sqlclient\ef и померяй его быстродействие. Я еще давно подобное делал, получилось около 8 на локальной машине. Это без кеширования. Прикрутив грамотное кеширование станет еще меньше.
Здравствуйте, Doc, Вы писали:
IT>>Т.е. практика показывает, что идея персистентности оказалось несостоятельной, а вместе с ней и идея жирных ORM. Doc>ASP.NET MVC (приведенная вами как пример) отлично работает в паре с EF. Более того, проект по умолчанию уже содержит EF.
Работает в паре не означает использует все возможности.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, matumba, Вы писали:
IT>>Работа с самой БД организуется как с персистентным объектным хранилищем, а как простые функции загрузки и сохранения данных. M>"Я извиняюсь!..."(ц) А в чём отличие "персистентности" от "загрузки/сохранения"?
В "персистентности" загрузка/сохранение — это лишь малая часть. Плюс к этому мы получаем UoW, change racking, object identity и другие entity services, которые по назначению не используются, но с аппетитом пожирают производительность приложения.
Если нам не помогут, то мы тоже никого не пощадим.