Оптимизируйте Entity Framework Query, избегайте отложенной загрузки

У меня есть запрос linq, который занимает несколько секунд (~2,6 с) для запуска. Но я хочу уменьшить это до минимума.

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

Я также проверил запрос без операторов include, но мои операции после запроса get еще больше замедлили его, поэтому я оставил 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, не включая "включенные"

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

Обновить

_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();

В основном я удалил предложение where, которое фильтрует год (я делаю это позже, для включения года), я добавил предложение Where, которое указывает рынок из getgo.

Я удалил Включить, который содержал рынок.

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

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

1 ответ

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

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

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

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 я использую include, потому что существует отношение 1 к 1, я избегаю слишком большого количества соединений, и поэтому мои множественные запросы будут выполняться быстрее, чем один, использующий include. Я не включаю Comms в первый запрос, чтобы попытаться избежать второго запроса, суть в том, что в этом случае 2 запроса выполняются быстрее, чем один.

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

Другие вопросы по тегам