我正在使用EF 6从数据库获取产品。产品类别被映射为产品的导航属性,数据来自ProductCategory透视表。这些类别像树一样工作(即每个类别都可以有子类别),但只有最具体的产品-子类别关系存储在透视表中。例如,假设有这样的类别路径:
电子产品 > 音频 > 功放 > 集成功放。
作为集成功放器的产品在透视表中有一条记录,记录了它的产品ID和集成功放类别ID。
我需要按类别筛选,但即使按父级类别进行筛选,产品也应该出现在列表中,例如,一个集成功放器应该出现在功放器列表中。因此,首先我制作一个相关类别ID列表。(这涉及到对类别表的单独查询,但不会花费太长时间。)如果类别过滤器是功放器,则列表是功放器的ID和集成功放器的ID。
问题是,当我包含筛选器时,产品查询需要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()的组合可以快速处理大量记录,但是在products中只有22个项目,在pl.categories中只有1-3个项目,在currentCategoryIdAndChildren中只有1-5个项目。我很惊讶,即使只有这么少的记录,它也比其它方法慢了一个数量级。以这种速度,我最好在客户端进行过滤,尽管这意味着返回了很多不必要的记录。
我是否遗漏了什么?还有其他方法吗?
更新:Express Profiler报告数据库查询本身仅花费3ms,因此我猜测性能与Entity Framework的工作方式有关。确切地说,第一次运行LINQ时它是最慢的(我知道它需要编译查询),但是即使在后续调用中,它仍然相对较慢。