实体框架-如何优化“包含”语句

本文关键字:包含 语句 优化 框架 何优化 实体 | 更新日期: 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));

如果您不介意使用物理表,可以使用半临时表。基本思想是:

  1. 创建具有"查询id"列的物理表
  2. 生成唯一ID(不是随机,而是唯一
  3. 在表中插入数据,用查询ID标记记录
  4. 将查询id传递给主查询,使用它联接到链接表
  5. 查询完成后,删除临时记录

最坏的情况是,如果出现问题,链接表中会有孤立的记录(这就是使用唯一查询ID的原因)。

这不是最干净的解决方案,但如果有很多值需要检查,它将比使用Contains更快。

当实体框架开始成为性能瓶颈时,通常是时候编写实际的SQL了。

例如,您可以构建一个表值函数,该函数以的表值参数(ID列表)作为参数。函数只会返回JOIN的结果。

表值函数功能需要EF5,所以如果您真的被EF4卡住了,它可能不是一个选项。

这个想法是重构查询以摆脱idList

例如,您应该返回来自法国的18-25岁男性用户的订单列表。如果你按年龄、性别和国家/地区过滤用户表,得到700多个id的用户的idList。相反,您可以使Orders表与Users联接,并对Users表应用筛选器。因此,您没有两个请求(一个用于id,一个用于order),而且它的工作速度要快得多,因为它可以在联接表时使用索引。

有道理吗?