2015-02-24 2 views
2

У меня есть запрос linq, который занимает пару секунд (~ 2.6s) для запуска. Но я хочу уменьшить это как можно меньше.Оптимизация структуры сущности Запрос, избегайте ленивой загрузки

Мне нужно только чтение, поэтому я включил поведение .AsNoTracking().

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

Основная цель состоит в том, чтобы уменьшить разговор в базе данных, а также инструкции ToList(), Include.

Код:

var obj = _context.MyContextModel.AsNoTracking() 
      .Where(x => x.CategoryList.Model.Id == 1) 
      .Where(x => x.CategoryList.Model.TypeId == 1) 
      .Where(x => x.Year.Select(y=>y.Datetime).Any(item => item.Year == 2010)) 
      .Include(x => x.LinkedMarket).AsNoTracking() 
      .Include(x => x.Year).AsNoTracking() 
      .Include(x => x.CategoryList).AsNoTracking() 
      .Include(x => x.CategoryList.Model).AsNoTracking(); 

return obj.AsParallel().ToList(); 

Эта операция обычно возвращается около 1000-2000 MyContextModel записи, не включая "включает в себя"

Как я могу оптимизировать это дальше? Должен ли я загружать объекты в класс контейнера? или другое решение?

Update

_context.Configuration.ProxyCreationEnabled = false; 
_context.Configuration.LazyLoadingEnabled = false; 
var obj = _context.MyContextModel.AsNoTracking() 
       .Where(x => x.CategoryList.Model.Id == 1) 
       .Where(x => x.CategoryList.Model.TypeId == 1) 
       .Where(x => x.LinkedMarket.FirstOrDefault(mar=>mar.MarketID == marketId) != null) 
       .Include(x => x.Year).AsNoTracking() 
       .Include(x => x.CategoryList).AsNoTracking() 
       .Include(x => x.CategoryList.Model).AsNoTracking(); 

return obj.AsParallel().ToList(); 

В основном я удалил, где положение какого фильтр года (я это позже, для этого включаемого года) Я добавил ИНЕК, задающий рынок от .

Я удалил Include, который содержал рынок.

Один большой вор производительность была на Linked рынке (я не знаю точно, почему, что-то EF не нравится.)

Это уменьшило запрос о среднем на 0,4 секунды. И вся операция установлена ​​с 4 + секунд до потрясающего 0,7 секунды.

+3

Вы анализировали сгенерированный запрос на отсутствие индексов и т. Д. В SSMS? – ErikEJ

+0

что-то скажите мне, что проблема прямо там. Где (x => x.Year.Select (y => y.Datetime). Любой (item => item.Year == 2010)) – Fredou

+0

@ErikEJ. У меня нет контроля над БД, поэтому я все равно ничего не могу изменить. –

ответ

2

Каждый из них включает в себя соединение, выполняемое в db. Предположим, что ваш левый стол имеет большой размер 1024 байта в размере записи и что у вас много деталей, скажем 1000, и что размер размерной записи составляет всего 100. Это приведет к повторному повторению информации для левой таблицы 1000 раз, эта информация будет помещена в провод db, и EF должен отфильтровать дублированный, чтобы создать ваш левый экземпляр.

Может быть лучше не использовать include и выполнять явную загрузку. В основном выполняется 2 запроса в одном контексте.

У меня есть пример использования этого принципа ниже. Это может быть в 10 раз быстрее, чем полагаться на include. (БД может обрабатывать только limitited число объединений эффективно кстати)

var adressen = adresRepository 
       .Query(r => r.RelatieId == relatieId) 
       .Include(i => i.AdresType) 
       .Select().ToList(); 

var adresids = (from a in adressen select a.AdresId).ToList(); 
      IRepositoryAsync<Comm> commRepository = unitOfWork.RepositoryAsync<Comm>(); 

      var comms = commRepository 
       .Query(c => adresids.Contains(c.AdresId)) 
       .Include(i => i.CommType) 
       .Select(); 

Для commType и adresType я использую включать, потому что есть 1 к 1 отношения, Я избегаю слишком много соединений и, таким образом, мои многочисленные запросы будут быть быстрее, чем использовать один из них. Я не включаю Comms в первый запрос, чтобы попытаться избежать второго запроса, дело в том, что в этом случае 2 запроса быстрее, чем один.

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

+0

Мне кажется, что EF должен быть достаточно прочным, чтобы человеку не приходилось кодировать несколько запросов для своевременного возврата данных. Это добавляет больше головных болей. – Kixoka

+1

@ Kix, EF не заменяет скромного разработчика, которому необходимо знать механизм, который существует, и должен использовать свой здравый смысл. Включение объединяется, и это имеет последствия. EF не может сделать это иначе, потому что ему нужно будет знать данные. –

+0

Так как дизайнером вы можете использовать либо ленивую загрузку, либо загрузку, либо явную загрузку. Дизайнер решает и выполняет тесты производительности по своим запросам. –

Смежные вопросы