Entity Framework mergeoption notrecking bad performance

У меня странное поведение, пытающееся выполнить запрос, объявляющий ObjectQuery MergeOption на "NoTracking", в этом случае структура сущности не должна прикреплять какую-либо сущность и не создавать относительный объект ObjectStateEntry для отслеживания состояния объекта.

Проблема заключается в том, что вместо повышения производительности это становится хуже, тот же запрос занимает 10 секунд с использованием mergeoption по умолчанию (то есть AppendingOnly) и более 1 минуты, если я попытаюсь указать notracking

Есть ли у кого-нибудь объяснения?

Ответ 1

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

Это означает, что потенциально гораздо больше объектов - многие с одним и тем же ключом - будут материализованы.

Пример. Предположим, у вас есть объект User с коллекцией Roles качестве свойства навигации. Также предположим, что у вас есть 1 миллион пользователей в базе данных, и все пользователи находятся в одних и тех же 10 ролях, т.е. у каждого пользователя есть коллекция ролей с 10 элементами. Если вы выполните следующий запрос...

var users = context.Users.Include("Roles").ToList();

... количество материализованных и созданных экземпляров объектов зависит от опции слияния:

  • Если вы не используете NoTracking вас будет 1.000.010 объектов в памяти, а именно 1 миллион пользователей, но только 10 ролей, потому что отображение идентичности гарантирует, что только 1 роль на ключ будет материализована и присоединена к контексту. Те же 10 экземпляров ролей используются для всей коллекции пользовательских Roles.

  • Однако, если вы используете NoTracking, EF не будет прикреплять объекты к контексту, поэтому управление идентификацией отключено, и у вас будет 11 000 000 объектов в памяти: 1 миллион пользователей и 10 экземпляров ролей на пользователя, то есть 10 миллионов объектов ролей. Таким образом, у вас в 10 раз больше материализованных объектов, чем когда объекты привязаны к контексту.

Материализация объекта относится к категории "умеренных" эксплуатационных расходов:

Операция: материализация объектов
Относительная стоимость: умеренная
Частота: один раз для каждого объекта, возвращаемого запросом.

Комментарии: процесс чтения возвращенного объекта DbDataReader, создания объектов и установки значений свойств, основанных на значениях в каждом экземпляре класса DbDataRecord. Если объект уже существует в ObjectContext и запрос использует параметры слияния AppendOnly или PreserveChanges, этот этап не влияет на производительность.

Другими словами: если в запросе используется NoTracking слияния NoTracking, этот этап влияет на производительность, и возможно, что преимущества в производительности от отключенного отслеживания изменений будут разрушены недостатками отключенного управления идентификацией и умноженной материализации объекта.