具有 LINQ 的实体框架在 WHERE 子句中使用 CONTAINS 非常慢且具有大整数列表

Posted

技术标签:

【中文标题】具有 LINQ 的实体框架在 WHERE 子句中使用 CONTAINS 非常慢且具有大整数列表【英文标题】:Entity Framework with LINQ using CONTAINS in WHERE clause very slow with large integer list 【发布时间】:2013-08-14 06:50:59 【问题描述】:

我有一个函数,它首先查询数据库中的一个函数,该函数返回一个允许用户查看的员工列表。这在几毫秒内运行。使用此列表,我查询员工表以获取允许该用户查看的所有员工。当我在查询分析器中运行生成的 sql 时,只需要几毫秒。当它从实体框架运行时,它需要超过 8 秒。

最初我有一个 allowedEmployees 列表,但随后阅读 http://mikeinba.blogspot.ca/2009/09/speeding-up-linq-contains-queries-with.html 并尝试使用 HashSet 代替,但性能仍然非常糟糕。如何获得与 sql 查询分析器中的性能相似的性能?我做错了什么?

我正在使用 SQL 2008 和 EF5.0

public IQueryable<Employee> FindAllByWithPermissions(int eID, Expression<Func<Employee, bool>> predicate)
    
        if (predicate != null)
        
            HashSet<int> allowedEmployees = SecurityRepository.GetPermissableEmployees(eID);
            return DataContext.Set<Employee>().Where(predicate).Where(p => allowedEmployees.Contains(p.EmployeeID)).AsQueryable<Employee>(); ;
        
        throw new ArgumentNullException("Predicate value must be passed to FindBy<T,TKey>.");
    

好像写sql有IN子句的时候需要很长的时间。有几千个允许的员工,但为什么生成 sql 需要这么长时间?

【问题讨论】:

嘿,你能在实际查询周围放一些计时器代码并将其与 SSMS 进行比较,它总是可以衡量差异是什么。它还可以帮助您了解何时更好 现在查询运行需要 10799 毫秒。在 SQL 查询分析器中,它需要不到一毫秒。允许的员工列表中大约有 5500 条记录。 你的代码中哪里有计时器块,它就在DataContext.Set&lt;Employee&gt;().Where(predicate)....附近? 我把它包裹在对 FindAllByWithPermissions 的调用中 【参考方案1】:

返回 IQueryable 而不是 HashSet,然后将 join 与您的员工 IQueryable 一起返回。

var availableEmployees = SecurityRepository.GetPermissableEmployees(eID);
var allEmployees= DataContext.Set<Employee>();

query = from item in allEmployees.Where(predicate)
        join t in availableEmployees on item.EmployeeID equals t.EmployeeID
        select item;

【讨论】:

GetPermissableEmployee 函数调用 SQL 函数来获取列表。据我所知,您无法将 sql 函数映射到实体框架中。 dbContext.Database.SqlQuery("SELECT * FROM DBO.GetPermissableEmployees(@ID)", new SqlParameter("ID", eID)).ToList() Database.SqlQuery 返回一个IEnumerable,它支持所有的 linq 方法。只需删除 ToList() 调用即可。 将其更改为 IEnumerable 或 IQueryable 的影响可以忽略不计 您是否包含了我在上面发布的用于创建连接而不是使用Contains 的代码? 我决定只使用数据库中的一个表来存储这些值。这让我可以做一个加入。将其从 10 多秒缩短到 2 毫秒以获得我的结果。感谢您的帮助和想法

以上是关于具有 LINQ 的实体框架在 WHERE 子句中使用 CONTAINS 非常慢且具有大整数列表的主要内容,如果未能解决你的问题,请参考以下文章

linq 到实体,where 子句中的 where ? (内凡)

实体框架 Linq 查询:.Where 链 vs &&

自动将一些 Where 子句添加到 Linq 表达式树

实体框架 .Any 不生成预期的 SQL WHERE 子句

C# 实体框架 OrderBy Children's Children's with a where 子句

LINQ 实体 Where 子句不在正确位置