Ошибка DbContext Query в сравнении с ObjectContext
Недавно я перенес мою модель объекта из ObjectContext, используя 4.1 в DbContext, используя 5.0. Я начинаю сожалеть об этом, потому что замечаю очень низкую производительность по запросу, используя DbContext vs ObjectContext. Здесь тестовый сценарий:
Оба контекста используют одну и ту же базу данных с примерно 600 таблицами. LazyLoading и ProxyCreation отключены для обоих (не показаны в примере кода). Оба имеют предварительно сгенерированные представления.
Тест сначала делает 1 вызов для загрузки рабочего пространства метаданных. Затем в цикле for, который выполняется 100 раз, я обновляю контекст и делаю один вызов, который принимает первый 10. (Я создаю контекст внутри цикла for, потому что это имитирует использование в службе WCF, что создаст контекст каждый раз)
for (int i = 0; i < 100; i++)
{
using (MyEntities db = new MyEntities())
{
var a = db.MyObject.Take(10).ToList();
}
}
Когда я запускаю это с ObjectContext, он занимает около 4,5 секунд. Когда я запускаю его с помощью DbContext, это занимает около 17 секунд. Я профилировал это с использованием профилировщика производительности RedGate. Для DbContext кажется, что основным виновником является метод UpdateEntitySetMappings. Это вызывается для каждого запроса и, как представляется, извлекает метаданные и просматривает каждый элемент в OSpace. AsNoTracking не помогло.
EDIT: Чтобы дать более подробную информацию, проблема связана с созданием\инициализацией DbSet и ObjectSet, а не с фактическим запросом. Когда я делаю вызов с ObjectContext, для создания ObjectSet требуется в среднем 42 мс. Когда я звоню с DbContext, для создания внутреннего dbset требуется около 140 мс. Оба объекта ObjectSet и DbSet выполняют некоторые сопоставления сопоставления сущностей из метаданных. Я заметил, что DbSet делает это для ВСЕХ типов в рабочей области, а ObjectSet - нет. Я предполагаю (не пробовал), что модель с меньшим количеством таблиц отличается от разницы в производительности.
Ответы
Ответ 1
Меня также беспокоит недооценка первого подхода к коду, и я выполнил некоторые тесты в сценарии, аналогичном вашему
http://netpl.blogspot.com/2013/05/yet-another-orm-micro-benchmark-part-23_15.html
Результаты не были сюрпризом, поскольку DbContext является оберткой над ObjectContext, он должен пожертвовать производительностью для простоты. Однако мои тесты показывают, что:
- Чем больше записей вы получите, тем меньше разница.
- чем больше записей вы получите, тем более важно отключить отслеживание, если вы хотите быть быстрее
Например, извлечение всего 10 записей
![enter image description here]()
Обратите внимание, что код сначала значительно медленнее, чем первая модель, и нет заметной разницы между отслеживанием и отсутствием отслеживания - оба наблюдения в точности совпадают с вашими.
Однако при извлечении 10000 строк у вас есть
![enter image description here]()
Обратите внимание, что почти нет разницы между первым кодом и моделью в версии notracking. Кроме того, оба они работают на удивление хорошо, почти так же быстро, как исходный datareader ado.net.
Пожалуйста, следуйте за моей записью в блоге для более подробной информации.
Этот простой тест помог мне сначала принять природу кода. Я по-прежнему предпочитаю его для небольших проектов из-за двух особенностей: poco-сущностей и миграций. С другой стороны, я бы никогда не выбрал ни одного из них для проекта, где производительность является критическим требованием. Это фактически означает, что я, вероятно, никогда больше не буду использовать первый подход к модели.
(Замечание: мой тест также показывает, что с nHibernate что-то не так. Я все еще не нашел никого, кто мог бы мне объяснить это, хотя я консультировался с двумя независимыми разработчиками, которые ежедневно используют NH)
Ответ 2
DbContext - это оболочка для ObjectContext. Вот хороший ответ о вашем вопросе. Возможно, что для облегчения использования они пожертвовали производительностью.
Ответ 3
Я использую Simple.Data для запроса миллионов записей, и он работает довольно хорошо и быстро.