LINQ to Entities Any () и Contains () медленно с небольшим списком
Я использую EF 6 для получения продуктов из базы данных. Категории продуктов отображаются как свойства навигации по продуктам, а данные взяты из сводной таблицы ProductCategory. Категории работают как дерево (т. Е. Каждая категория может иметь подкатегории), но в сводной таблице хранится только наиболее конкретное отношение продукт-подкатегория. Например, предположим, что есть путь категории:
Электроника> Аудио> Усилители> Интегрированные усилители.
Продукт, который является встроенным усилителем, имеет запись в сводной таблице с идентификатором продукта и идентификатором категории встроенных усилителей.
Мне нужно отфильтровать по категории, но продукт должен отображаться даже при фильтрации по родительской категории, например, интегрированный усилитель должен появиться в списке усилителей. Итак, сначала я делаю список соответствующих идентификаторов категорий. (Это включает в себя отдельный запрос к таблице категорий, но это не займет много времени.) Если в качестве фильтра категории выбран «Усилители», список представляет собой идентификатор усилителей и идентификатор встроенных усилителей.
Проблема в том, что запрос товаров в 10-20 раз дольше, когда я включаю фильтр:
List<int> currentCategoryIdAndChildren = BuildCategoryIdList(currentCategoryId);
using (var db = new myContext())
{
var products = db.Products
.Select(p => new Product_PL
{
id = p.ID,
name = p.Name,
description = p.Description,
categories = p.Categories
.Select(c => new Category_PL
{
categoryid = c.ID,
}),
});
// Filter by category
products = products.Where(pl => pl.categories.Any(c => currentCategoryIdAndChildren.Contains(c.categoryid)));
// Other filters, sorting, and paging here
rptProducts.DataSource = products.ToList(); // Database call is made here
rptProducts.DataBind();
}
Я ожидаю, что комбинация Any () и Contains () быстро замедлится с большим количеством записей, но я работаю с 22 элементами в продуктах, 1-3 элементами в pl.categories и 1-5 элементами в currentCategoryIdAndChildren , Я удивлен, что с таким небольшим количеством записей это на порядок медленнее. В таком случае мне лучше отфильтровывать его на стороне клиента, хотя это означает, что нужно возвращать много ненужных записей.
Я что-то упускаю? Есть ли другой подход?
ОБНОВИТЬExpress Profiler сообщает, что сам запрос к базе данных занимает всего 3 мс, поэтому я предполагаю, что производительность как-то связана с тем, как работает Entity Framework. Конечно, он самый медленный в самый первый раз, когда запускается LINQ (я знаю, что он должен скомпилировать запрос), но он все еще относительно медленный при последующих вызовах.