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.