Entity Framework слишком медленная. Какие у меня варианты?
Я выполнил мантру "Не оптимизируйте преждевременно" и закодировал мою службу WCF с помощью Entity Framework.
Однако я профилировал производительность, а Entity Framework - слишком медленно. (Мое приложение обрабатывает 2 сообщения примерно через 1,2 секунды, когда (предыдущее) приложение, которое я переписываю, одновременно делает 5-6 сообщений. (Унаследованное приложение вызывает sprocs для своего доступа к базе данных.)
Мои профилирующие точки для Entity Framework берут большую часть времени на сообщение.
Итак, каковы мои варианты?
-
Есть ли там лучшие ORM?
(Что-то, что просто поддерживает нормальное чтение и запись объектов и делает это быстро..)
-
Есть ли способ сделать Entity Framework быстрее?
( Примечание: когда я говорю быстрее, я имею в виду в долгосрочной перспективе, а не первый вызов. (Первый вызов медленный (15 секунд для сообщения), но это не проблема. Мне просто нужно это будет быстро для остальных сообщений.)
-
Некоторые загадочные 3-й вариант, который поможет мне получить больше скорости от моего обслуживания.
ПРИМЕЧАНИЕ.. Большинство взаимодействий с БД или создание и обновление. Я очень мало выбираю и удаляю.
Ответы
Ответ 1
Вы должны начать с профилирования SQL-команд, фактически выпущенных Entity Framework. В зависимости от вашей конфигурации (объекты POCO, Self-Tracking) есть много возможностей для оптимизации. Вы можете отлаживать SQL-команды (которые не должны отличаться от режима отладки и выпуска) с помощью метода ObjectSet<T>.ToTraceString()
. Если вы столкнулись с запросом, который требует дальнейшей оптимизации, вы можете использовать некоторые прогнозы, чтобы дать EF дополнительную информацию о том, что вы пытаетесь выполнить.
Пример:
Product product = db.Products.SingleOrDefault(p => p.Id == 10);
// executes SELECT * FROM Products WHERE Id = 10
ProductDto dto = new ProductDto();
foreach (Category category in product.Categories)
// executes SELECT * FROM Categories WHERE ProductId = 10
{
dto.Categories.Add(new CategoryDto { Name = category.Name });
}
Может быть заменено на:
var query = from p in db.Products
where p.Id == 10
select new
{
p.Name,
Categories = from c in p.Categories select c.Name
};
ProductDto dto = new ProductDto();
foreach (var categoryName in query.Single().Categories)
// Executes SELECT p.Id, c.Name FROM Products as p, Categories as c WHERE p.Id = 10 AND p.Id = c.ProductId
{
dto.Categories.Add(new CategoryDto { Name = categoryName });
}
Я просто набрал это из головы, так что это не совсем так, как это будет выполнено, но EF действительно делает некоторые хорошие оптимизации, если вы расскажете все, что знаете о запросе (в этом случае нам понадобятся имена категорий). Но это не похоже на загрузку (db.Products.Include( "Категории" )), потому что прогнозы могут дополнительно уменьшить объем загружаемых данных.
Ответ 2
Дело в том, что такие продукты, как Entity Framework, будут ВСЕГДА быть медленными и неэффективными, потому что они выполняют намного больше кода.
Я также считаю глупым, что люди предполагают, что нужно оптимизировать запросы LINQ, посмотреть на сгенерированный SQL, использовать отладчики, предварительно скомпилировать, сделать много дополнительных шагов и т.д., т.е. тратить много времени. Никто не говорит - Упростите! Все хотят соединить вещи дальше, делая еще больше шагов (теряя время).
Подход, основанный на здравом смысле, заключался бы в том, чтобы не использовать EF или LINQ вообще. Используйте простой SQL. В этом нет ничего плохого. Просто потому, что среди программистов есть менталитет стада, и они чувствуют желание использовать каждый новый продукт там, не означает, что это хорошо или оно будет работать. Большинство программистов думают, что если они включают в себя все новые части кода, выпущенные крупной компанией, это делает их более умным программистом; не совсем. Умное программирование в основном связано с тем, как делать больше с меньшими головными болями, неопределенностями и наименьшим количеством времени. Помните - Время! Это самый важный элемент, поэтому постарайтесь найти способы не тратить его на решение проблем с плохим/раздутым кодом, написанным просто для того, чтобы соответствовать некоторым странным так называемым "шаблонам"
Расслабьтесь, наслаждайтесь жизнью, перейдите от кодирования и прекратите использовать дополнительные функции, код, продукты, "шаблоны". Жизнь коротка, а жизнь вашего кода еще короче, и это, конечно, не ракетостроение. Удалите слои, такие как LINQ, EF и другие, и ваш код будет работать эффективно, масштабируется, и да, он будет по-прежнему прост в обслуживании. Слишком большая абстракция - плохой "шаблон".
И это решение вашей проблемы.
Ответ 3
Одно из предложений - использовать LINQ to Entity Framework только для заявлений CRUD с одной записью.
Для получения дополнительных запросов, поиска, отчетов и т.д. запишите хранимую процедуру и добавьте ее в модель Entity Framework, как описано в MSDN.
Это подход, который я сделал с несколькими моими сайтами, и, похоже, это хороший компромисс между производительностью и производительностью. Entity Framework не всегда будет генерировать наиболее эффективный SQL для этой задачи. И вместо того, чтобы тратить время на то, чтобы понять, почему писать хранимую процедуру для более сложных запросов на самом деле экономит время для меня. После того, как вы знакомы с процессом, не слишком много хлопот, чтобы добавить хранимые процедуры в вашу модель EF. И, конечно, преимущество добавления его в вашу модель заключается в том, что вы получаете все, что сильно набрало доброту, которое исходит от использования ORM.
Ответ 4
Если вы извлекаете данные исключительно из-за больших затрат, то это означает, что EF не позволяет отслеживать объекты, которые он получает. Сделайте это, используя MergeOption.NoTracking. EF будет просто генерировать запрос, выполнять его и десериализовать результаты на объекты, но не будет пытаться отслеживать изменения сущности или что-либо в этом роде. Если запрос прост (не тратит много времени, ожидая возвращения базы данных), я обнаружил, что установка его в NoTracking может удвоить производительность запросов.
См. статью MSDN в перечислении MergeOption:
Разрешение имен, управление состоянием и отслеживание изменений
Это, кажется, хорошая статья о производительности EF:
Производительность и инфраструктура Entity
Ответ 5
Вы говорите, что вы профилировали приложение. Вы тоже профилировали ORM? Существует профилировщик EF от Ayende, который выделит, где вы можете оптимизировать свой EF-код. Вы можете найти его здесь:
http://efprof.com/
Помните, что вы можете использовать традиционный подход SQL наряду с ORM, если вам нужно повысить производительность.
Если есть более быстрый/лучший ORM? В зависимости от модели объекта/данных вы можете использовать один из микро-ORM, например Dapper, Massive или PetaPoco.
Сайт Dapper публикует сравнительные тесты, которые дадут вам представление о том, как они сравниваются с другими ORM. Но стоит отметить, что микро-ORM не поддерживают богатый набор функций для всех ORM, таких как EF и NH.
Вы можете взглянуть на RavenDB. Это нереляционная база данных (от Айенде снова), которая позволяет вам напрямую хранить POCO без привязки . RavenDB оптимизирован для чтения и упрощает жизнь разработчиков, устраняя необходимость манипулировать схемой и сопоставлять объекты с этой схемой. Однако имейте в виду, что это существенно другой подход к использованию подхода ORM, и они описаны в сайте продукта.
Ответ 6
Я нашел ответ от @Slauma здесь, очень полезный для ускорения событий. Я использовал один и тот же шаблон для обеих вставок и обновлений - и производительность взлетела.
Ответ 7
Из моего опыта проблема не с EF, а с самим ORM-подходом.
В общем, все ORM страдают от проблемы N + 1 не оптимизированными запросами и т.д. Мое лучшее предположение - отслеживать запросы, которые приводят к ухудшению производительности и пытаются настроить -up ORM или переписать эти части с помощью SPROC.
Ответ 8
Оптимизируется только после того, как вы профилировали. Если вы обнаружите, что доступ к DB медленный, вы можете преобразовать его в использование хранимых процедур и сохранить EF. Если вы обнаружите, что сам EF замедляется, вам, возможно, придется переключиться на другую ORM или вообще не использовать ORM.
Ответ 9
Это простой вариант без рамки, без ORM, который загружается со скоростью 10 000 в секунду с 30 полями или около того. Запуск на старом ноутбуке, возможно, быстрее, чем в реальной среде.
https://sourceforge.net/projects/dopersistence/?source=directory
Ответ 10
Я столкнулся с этой проблемой. Мне не нравится сбрасывать EF, потому что он работает так хорошо, но он просто медленный. В большинстве случаев я просто хочу найти запись или обновить/вставить. Даже простые операции, подобные этому, медленны. Я отменил 1100 записей из таблицы в список, и эта операция заняла 6 секунд с EF. Для меня это слишком долго, даже экономия занимает слишком много времени.
В итоге я создал свой собственный ORM. Я вытащил те же 1100 записей из базы данных, и мой ORM занял 2 секунды, намного быстрее, чем EF. Все с моим ORM почти мгновенно. Единственное ограничение прямо сейчас заключается в том, что он работает только с MS SQL Server, но его можно изменить для работы с другими, такими как Oracle. Я использую MS SQL Server для всего прямо сейчас.
Если вы хотите попробовать мой ORM, вот ссылка и веб-сайт:
https://github.com/jdemeuse1204/OR-M-Data-Entities
Или, если вы хотите использовать самородок:
PM > Install-Package OR-M_DataEntities
Документация также находится там
Ответ 11
Entity Framework не должна вызывать серьезные узкие места. Скорее всего, есть и другие причины. Вы можете попытаться переключить EF на Linq2SQL, у обоих есть сравнение функций, и код должен быть легко конвертирован, но во многих случаях Linq2SQL быстрее, чем EF.
Ответ 12
У нас есть аналогичное приложение (Wcf → EF → database), которое легко выполняет 120 запросов в секунду, поэтому я более чем уверен, что EF не является вашей проблемой здесь, поскольку, как говорится, я видел значительные улучшения производительности с помощью скомпилированные запросы.
Ответ 13
Я использовал EF, LINQ to SQL и dapper. Даппер самый быстрый.
Пример: мне потребовалось 1000 основных записей с 4 подзаголовками. Я использовал LINQ для sql, это заняло около 6 секунд. Затем я переключился на dapper, извлек 2 набора записей из одной хранимой процедуры и для каждой записи добавили подзаголовки. Общее время 1 секунда.
Кроме того, функции хранимых процедур, используемые функцией табличного значения с применением cross apply, я нашел, что функции скалярных значений очень медленные.
Моим советом было бы использовать EF или LINQ to SQL и для определенных ситуаций переключиться на dapper.