Как улучшить производительность LINQ to EF - PullRequest
4 голосов
/ 19 декабря 2011

У меня есть два класса: Property и PropertyValue. Свойство имеет несколько значений, где каждое значение является новой ревизией.

При получении набора свойств я хочу включить самую последнюю версию значения для каждого свойства.

в T-SQL это очень эффективно можно сделать так:

SELECT 
p.Id,
pv1.StringValue,
pv1.Revision
FROM dbo.PropertyValues pv1
LEFT JOIN dbo.PropertyValues pv2 ON pv1.Property_Id = pv2.Property_Id AND pv1.Revision < pv2.Revision
JOIN dbo.Properties p ON p.Id = pv1.Property_Id
WHERE pv2.Id IS NULL
ORDER BY p.Id

"Волшебство" в этом запросе состоит в том, чтобы присоединиться к условию меньше условия и искать строки без результата, вызванного LEFT JOIN.

Как я могу сделать что-то подобное, используя LINQ to EF?

Лучшее, что я мог придумать, было:

from pv in context.PropertyValues
group pv by pv.Property into g
select g.OrderByDescending(p => p.Revision).FirstOrDefault()

Это дает правильный результат, но примерно в 10 раз медленнее, чем другие.

Ответы [ 3 ]

1 голос
/ 19 декабря 2011

Помимо оптимизации запроса в Linq To Entities, вы также должны знать о работе, которую требует Entity Framework для преобразования вашего запроса в SQL, а затем сопоставить результаты с вашими объектами.

Сравнение запроса Linq To Entities напрямую с SQL-запросом всегда приводит к снижению производительности, поскольку Entity Framework делает для вас гораздо больше.

Поэтому важно также взглянуть на оптимизацию шагов, которые предпринимает Entity Framework.

Что может помочь:

  • Предварительная компиляция запроса
  • Предварительная генерация представлений
  • Решите сами, когда открывать соединение с базой данных
  • Отключить отслеживание (если необходимо)

Здесь вы можете найти документацию со стратегиями производительности.

1 голос
/ 19 декабря 2011

Может быть, это может помочь.Где db - это контекст базы данных:

(
            from pv1 in db.PropertyValues
            from pv2 in db.PropertyValues.Where(a=>a.Property_Id==pv1.Property_Id && pv1.Revision<pv2.Revision).DefaultIfEmpty()
            join p in db.Properties
                on pv1.Property_Id equals p.Id
            where pv2.Id==null
            orderby p.Id
            select new
            {
                p.Id,
                pv1.StringValue,
                pv1.Revision
            }
    );
0 голосов
/ 19 декабря 2011

если вы хотите использовать несколько условий (меньше выражения) в соединении, вы можете сделать это как

from pv1 in db.PropertyValues
 join pv2 in db.PropertyValues on new{pv1.Property_ID, Condition = pv1.Revision < pv2.Revision} equals new {pv2.Property_ID , Condition = true} into temp
from t in temp.DefaultIfEmpty()
            join p in db.Properties
                on pv1.Property_Id equals p.Id
            where t.Id==null
            orderby p.Id
            select new
            {
                p.Id,
                pv1.StringValue,
                pv1.Revision
            }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...