Entity Framework слишком медленная. Какие у меня варианты?

Я выполнил мантру «Не оптимизирую преждевременно» и закодировал мою службу WCF с помощью Entity Framework.

Однако я профилировал производительность, а платформа Entity Framework слишком медленная. (Мое приложение обрабатывает 2 сообщения примерно через 1,2 секунды, где (прежнее) приложение, которое я переписываю, делает 5-6 сообщений в одно и то же время. (Унаследованное приложение вызывает sprocs для своего доступа к БД).

Мои профилирующие точки для Entity Framework берут большую часть времени на сообщение.

Итак, каковы мои варианты?

  • Там лучше ORM?
    (Что-то, что просто поддерживает нормальное чтение и запись объектов и делает это быстро ..)

  • Есть ли способ сделать Entity Framework быстрее?
    ( Примечание : когда я говорю быстрее, я имею в виду в долгосрочной перспективе, а не в первом вызове. (Первый звонок медленный (15 секунд для сообщения), но это не проблема. Мне просто нужно, чтобы это было быстро для остальных сообщений.)

  • Какой-то загадочный третий вариант, который поможет мне получить больше скорости от моего обслуживания.

ПРИМЕЧАНИЕ. Большинство моих взаимодействий с БД – это «Создать и обновить». Я очень мало выбираю и удаляю.

Вы должны начать с профилирования SQL-команд, фактически выпущенных Entity Framework. В зависимости от вашей конфигурации (объекты POCO, Self-Tracking) есть много возможностей для оптимизации. Вы можете отлаживать SQL-команды (которые не должны отличаться от режима отладки и выпуска), используя метод ObjectSet.ToTraceString() . Если вы столкнулись с запросом, который требует дальнейшей оптимизации, вы можете использовать некоторые outlookы, чтобы дать 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 («Категории»)), потому что outlookы могут еще больше уменьшить объем загружаемых данных.

Дело в том, что такие продукты, как Entity Framework, будут ВСЕГДА быть медленными и неэффективными, потому что они выполняют намного больше кода.

Я также считаю глупым, что люди предлагают оптимизировать запросы LINQ, посмотреть на сгенерированный SQL, использовать отладчики, предварительно скомпилировать, принять много дополнительных шагов и т. Д., Т. Е. Тратить много времени. Никто не говорит – Упростите! Все хотят соединить вещи дальше, делая еще больше шагов (тратя время).

Общепринятым подходом было бы не использовать EF или LINQ вообще. Используйте простой SQL. В этом нет ничего плохого. Просто потому, что среди программистов есть менталитет стада, и они чувствуют желание использовать каждый новый продукт там, не означает, что это хорошо или оно будет работать. Большинство программистов думают, что если они include в себя все новые части кода, выпущенные крупной компанией, это делает их более умным программистом; не совсем. Умное программирование в основном связано с тем, как делать больше с меньшими головными болями, неопределенностями и наименьшим количеством времени. Помните – Время! Это самый важный элемент, поэтому постарайтесь найти способы не тратить его на решение проблем в плохом / раздутом коде, написанном просто, чтобы соответствовать некоторым странным так называемым «шаблонам»,

Расслабьтесь, наслаждайтесь жизнью, передохните от кодирования и прекратите использовать дополнительные функции, код, продукты, «шаблоны». Жизнь коротка, а жизнь вашего кода еще короче, и это, конечно, не ракетостроение. Удалите слои, такие как LINQ, EF и другие, и ваш код будет работать эффективно, масштабируется, и да, он будет по-прежнему прост в обслуживании. Слишком большая абстракция – плохой «шаблон».

И это решение вашей проблемы.

Одно из предложений – использовать LINQ to Entity Framework только для одноразовых CRUD-заявлений.

Для получения дополнительных запросов, поиска, отчетов и т. Д. Запишите хранимую процедуру и добавьте ее в модель Entity Framework, как описано в MSDN .

Это подход, который я использовал с несколькими моими сайтами, и это, по-видимому, хороший компромисс между производительностью и производительностью. Entity Framework не всегда будет генерировать наиболее эффективный SQL для этой задачи. И вместо того, чтобы тратить время на то, чтобы понять, почему писать хранимую процедуру для более сложных запросов на самом деле экономит время для меня. После того, как вы знакомы с процессом, не слишком много хлопот, чтобы добавить хранимые процедуры в вашу EF-модель. И, конечно же, преимущество добавления его в вашу модель состоит в том, что вы получаете все, что сильно набрало доброту, которая исходит от использования ORM.

Если вы просто извлекаете данные, это большая помощь в производительности, когда вы указываете EF не отслеживать объекты, которые он получает. Сделайте это, используя MergeOption.NoTracking. EF будет просто генерировать запрос, выполнять его и десериализовать результаты на объекты, но не будет пытаться отслеживать изменения сущности или что-либо в этом роде. Если запрос прост (он не тратит много времени, ожидая возвращения базы данных), я обнаружил, что установка его в NoTracking может удвоить производительность запроса.

См. Статью MSDN в перечислении MergeOption:

Разрешение идентичности, управление состоянием и отслеживание изменений

Это, по-видимому, хорошая статья о производительности EF:

Производительность и структура сущностей

Вы говорите, что вы профилировали приложение. Вы тоже профилировали ORM? Существует профилировщик EF от Ayende, который выделит, где вы можете оптимизировать свой EF-код. Вы можете найти это здесь:

http://efprof.com/

Помните, что вы можете использовать традиционный подход SQL наряду с ORM, если вам нужно повысить производительность.

Если есть более быстрый / лучший ОРМ? В зависимости от модели объекта / данных вы можете использовать один из микро-ORM, например Dapper , Massive или PetaPoco .

Сайт Dapper публикует сравнительные тесты, которые дадут вам представление о том, как они сравниваются с другими ORM. Но стоит отметить, что микро-ORM не поддерживают богатый набор функций для всех ORM, таких как EF и NH.

Вы можете взглянуть на RavenDB . Это нереляционная firebase database (от Айенде снова), которая позволяет вам хранить POCO напрямую, при этом не требуется сопоставление . RavenDB оптимизирован для чтения и упрощает жизнь разработчиков, устраняя необходимость манипулировать схемой и сопоставлять объекты с этой схемой. Однако имейте в виду, что это существенно другой подход к использованию подхода ORM, который описан на сайте продукта .

По моему опыту, проблема не с EF, а с самим ORM-подходом.

В общем, все ORM испытывают проблемы с N + 1, а не оптимизированные запросы и т. Д. Лучше всего было бы отследить запросы, которые приводят к ухудшению производительности, и попытаться настроить инструмент ORM или переписать эти части с помощью SPROC.

Я нашел ответ от @Slauma здесь очень полезный для ускорения событий. Я использовал один и тот же шаблон для обеих вставок и обновлений – и производительность взлетела.

После того, как вы профилировали, имеет смысл только оптимизировать. Если вы обнаружите, что доступ к DB медленный, вы можете преобразовать его в использование хранимых процедур и сохранить EF. Если вы обнаружите, что сам EF медленный, вам, возможно, придется переключиться на другую ORM или вообще не использовать ORM.

Это простой вариант без frameworks, без ORM, который загружается со скоростью 10 000 в секунду с 30 полями или около того. Работа на старом ноутбуке, возможно, быстрее, чем в реальной среде.

https://sourceforge.net/projects/dopersistence/?source=directory

Я столкнулся с этим вопросом. Мне не нравится сбрасывать EF, потому что он работает так хорошо, но он просто медленный. В большинстве случаев я просто хочу найти запись или обновить / вставить. Даже простые операции, подобные этому, медленны. Я отменил 1100 записей из таблицы в список, и эта операция заняла 6 секунд с EF. Для меня это слишком долго, даже экономия занимает слишком много времени.

Я закончил тем, что создал свою собственную ОРМ. Я вытащил те же 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

Документация также присутствует там

Entity Framework не должна вызывать серьезные узкие места. Скорее всего, есть и другие причины. Вы можете попытаться переключить EF на Linq2SQL, у обоих есть сравнение функций, а код должен быть легко конвертирован, но во многих случаях Linq2SQL быстрее, чем EF.

У нас есть аналогичное приложение (Wcf -> EF -> database), которое легко выполняет 120 запросов в секунду, поэтому я более чем уверен, что EF не является вашей проблемой здесь, так как я видел значительные улучшения производительности с скомпилированными запросами.

Я использовал EF, LINQ to SQL и dapper. Даппер самый быстрый. Пример: мне потребовалось 1000 основных записей с 4 подзаголовками. Я использовал LINQ для sql, это заняло около 6 секунд. Затем я переключился на dapper, извлек 2 набора записей из одной хранимой процедуры и для каждой записи добавили подзаголовки. Общее время 1 секунда.

Кроме того, в хранимой процедуре используются функции значения таблицы с использованием cross cross, я обнаружил, что функции скалярных значений очень медленные.

Моим советом было бы использовать EF или LINQ to SQL и для определенных ситуаций переключиться на dapper.

  • Entity Framework: запрос дочерних объектов
  • От многих до многих сопоставление с дополнительными полями в Fluent API
  • Отладка кода-первых кодов миграции Entity Framework
  • Создание поля First Date Framework
  • Entity Framework v2 не поддерживает sql 2000?
  • Тип или имя пространства имен «DbContext» не удалось найти
  • Группирование команд DB в Entity Framework 4.0
  • Отображение представлений базы данных в EF 5.0 Code First w / Migrations
  • EF Code First "Недопустимое имя столбца« Дискриминатор », но без наследования
  • Может ли кто-нибудь понять, почему я продолжаю получать эту ошибку, проверяя бета-версию EF 5
  • Первый код - сначала модель / firebase database
  • Давайте будем гением компьютера.