实体框架-如何优化“包含”语句
本文关键字:包含 语句 优化 框架 何优化 实体 | 更新日期: 2023-09-27 18:29:20
在我们当前的应用程序中,我们的一些查询存在一些性能问题。通常我们有这样的东西:
List<int> idList = some data here…;
var query = (from a in someTable where idList.Contains(a.Id));
虽然对于简单的查询来说,这是可以接受的,但当idList中有更多项目时(例如,在一些查询中,我们要检查大约700个id),这就成为了一个瓶颈。
除了Contains之外,还有其他方法可以使用吗?我们正在考虑使用一些临时表来首先插入Id,然后执行联接而不是Contains,但EntityFramework似乎不支持这样的操作(在代码中创建临时表):(
我们还能尝试什么?
I建议使用LINQ PAD,它提供了一个"转换为SQL"选项,允许您以SQL语法查看查询。
这有可能是最佳解决方案(如果你不喜欢乱七八糟的东西)。可能会尝试将idList作为排序数组,并用二进制搜索替换contains方法。(您可以实现自己的扩展)。
你可以试试这个:
var query = someTable.Where(a => idList.Any(b => b.Id == a.Id));
如果您不介意使用物理表,可以使用半临时表。基本思想是:
- 创建具有"查询id"列的物理表
- 生成唯一ID(不是随机,而是唯一)
- 在表中插入数据,用查询ID标记记录
- 将查询id传递给主查询,使用它联接到链接表
- 查询完成后,删除临时记录
最坏的情况是,如果出现问题,链接表中会有孤立的记录(这就是使用唯一查询ID的原因)。
这不是最干净的解决方案,但如果有很多值需要检查,它将比使用Contains
更快。
当实体框架开始成为性能瓶颈时,通常是时候编写实际的SQL了。
例如,您可以构建一个表值函数,该函数以的表值参数(ID列表)作为参数。函数只会返回JOIN
的结果。
表值函数功能需要EF5,所以如果您真的被EF4卡住了,它可能不是一个选项。
这个想法是重构查询以摆脱idList
。
例如,您应该返回来自法国的18-25岁男性用户的订单列表。如果你按年龄、性别和国家/地区过滤用户表,得到700多个id的用户的idList
。相反,您可以使Orders
表与Users
联接,并对Users
表应用筛选器。因此,您没有两个请求(一个用于id,一个用于order),而且它的工作速度要快得多,因为它可以在联接表时使用索引。
有道理吗?