Оптимизируем Запросы EF Core.
Продолжаем разговор о быстродействии запросов в EF Core. Существует множество правил оптимизации запросов, сегодня рассмотрим основные.
1. Выбирайте только нужные поля
Рассмотрим пример:
var employees = context.Employees
.Select(e => new EmployeeDto
{
Name = e.Name,
Email = e.Email
}).ToList();
В БД скорее всего будет больше 2 полей. Но нам не нужны остальные.
Преимущества
- Сокращает объём данных, передаваемых из БД в приложение, что поможет, особенно в распределенных средах.
- Снижает использование памяти приложения.
- БД может возвращать результат быстрее, например, за счёт покрывающих индексов.
- Уменьшаются накладные расходы на отслеживание изменений.
2. Избегайте N+1 запросов
Это происходит, когда ваше приложение выполняет один запрос для получения набора объектов, а затем дополнительные запросы для каждого объекта для получения связанных данных:
// Получаем все блоги - 1 запрос
var blogs = context.Blogs.ToList();
foreach (var b in blogs)
{
// Для каждого блога получаем посты
// N запросов
var posts = b.Posts;
foreach (var p in posts)
Console.WriteLine(p.Title);
}
Вместо этого используем «жадную загрузку»:
var blogs = context.Blogs
.Include(b => b.Posts).ToList();
foreach (var b in blogs)
{
foreach (var p in b.Posts)
Console.WriteLine(post.Title);
}
«Жадная» загрузка с помощью Include(b => b.Posts) сообщает EF Core загрузить посты, связанные с каждым блогом, как часть изначального запроса. Таким образом выполняется один запрос, который извлекает все блоги со связанными с ними постами. Поэтому во время итерации в цикле foreach не выполняются никакие дополнительные запросы.
Преимущества
- Значительное снижение нагрузки на БД и сеть (особенно при грамотной организации данных: индексы, внешние ключи).
- Упрощение логики кода, поскольку в нём явно указано намерение загрузить связанные данные.
3. Используйте AsNoTracking()
Этот метод особенно полезен, когда вы только считываете данные из базы. В следующем примере список продуктов извлекается без затрат на отслеживание изменений:
var products = context.Products
.AsNoTracking().ToList();
// Используем products только для чтения
Преимущества
- Особенно заметно в крупных приложениях или при работе с большими наборами данных. Запросы выполняются быстрее и потребляется меньше памяти.
- Сокращение накладных расходов, т.к. не требуется отслеживать изменения или сохранять информацию о состоянии объектов.
4. Используйте разделённые запросы с помощью AsSplitQuery().
Подробности здесь.
Источник: https://stefandjokic.tech/blog