EF Где (x => x.ColumnVal == 1) против FirstOrDefault (x => x.Column == 1) - PullRequest
6 голосов
/ 29 октября 2010

У меня был запрос LINQ, который загружает иерархию объектов, подобную следующей:

Запрос # 1

var result = db.Orders
               .Include("Customer")
               // many other .Include() here
               .FirstOrDefault(x => x.Customer.CustomerId == 1 &&
                                    x.OrderId == orderId);

У меня была ОСНОВНАЯ производительностьпроблема с этим.Загрузка процессора составляла около 100%, а использование памяти было очень высоким.

И я настроил это следующим образом, и проблема с производительностью была исправлена.

Запрос # 2

var result = db.Orders
               .Include("Customer")
               // many other .Include() here
               .Where(x => x.Customer.CustomerId == 1 &&
                           x.OrderId == orderId)
               .FirstOrDefault();

Я просто хочу подтвердить свое подозрение.Запрос № 1, вероятно, просматривает все мои записи в памяти в поисках подходящей записи против Запрос № 2 фильтрует записи в базе данных, а затем получает только первую запись.

Поэтому Query # 1 имеет проблемы с производительностью?

Чтобы быть в безопасности, нужно ли использовать .Select(x => x) перед .FirstOrDefault()?

Query # 3

var result = db.Orders
               .Include("Customer")
               // many other .Include() here
               .Where(x => x.Customer.CustomerId == 1 &&
                           x.OrderId == orderId)
               .Select(x => x)
               .FirstOrDefault();

Ответы [ 3 ]

3 голосов
/ 29 октября 2010

Нет, они оба должны приводить к одному и тому же запросу SQL при выполнении.Вы можете доказать это, заглянув в SQL Profiler и посмотрев, какой именно SQL-запрос отправляется из EF в обоих случаях.Ваша оптимизация производительности должна была быть вызвана некоторыми другими факторами.И вот почему:

Включить метод возвращает ObjectQuery :

public class ObjectQuery<T> : ObjectQuery, IOrderedQueryable<T>, 
                              IQueryable<T>, IEnumerable<T>, 
                              IOrderedQueryable, IQueryable, 
                              IEnumerable, IListSource

Что означает его FirstOrDefault метод поставляется с 2 перегрузками:

// Defined by Enumerable:
FirstOrDefault(Func<T, Boolean>)

// Defined by Queryable:
FirstOrDefault(Expression<Func<T, Boolean>>)

Когда вы кодируете .FirstOrDefault(x => x.Customer.CustomerId == 1, компилятор перейдет в процесс под названием Разрешение перегрузки для выводатип лямбда-выражения x => x.Customer.CustomerId == 1, поскольку он может быть преобразован в тип обоих типов параметров перегрузки.Компилятор будет использовать алгоритм (который я все еще пытаюсь найти в C # Language Specification!), Выяснить, что преобразование лямбды в Expression<Func<T, Boolean> является лучшим преобразованием , чем в Func<T, Boolean>, поэтому выберите перегрузку IQueryable .
Следовательно, вы увидите предикат в сгенерированном SQL при его наблюдении в SQL Profiler.

0 голосов
/ 11 марта 2015

Я думаю, что лучше всего было бы использовать ... Где ( условие ). Take (1) .FirstOrDefault (), потому что Take (1) можно легко перевести в SQL как предложение TOP. Кто-нибудь со мной?

0 голосов
/ 29 октября 2010

Я нашел виновника.Это SQL-запрос , сгенерированный Entity Framework.У меня сложная схема с множеством взаимосвязей «многие ко многим».

Entity Framework генерировал строку длиной *1006* строку SQL: '(Теперь я изменяю свой код для загрузки иерархии вручную для какой-то части.

Пожалуйста, дайте мне знать, если кто-нибудь знает хорошие статьи для прочтения об отношениях Eager Loading и Many-to-Many.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...