【问题标题】:Performance: .Join vs .Contains - Linq to Entities性能:.Join vs .Contains - Linq to Entities
【发布时间】:2017-03-31 17:58:00
【问题描述】:

我正在使用 Linq to entity 来查询数据库以获取 int 列表以进行进一步处理。我有两种方法可以得到如下列表:

首先是:

List<int> lstBizIds = new List<int>() { 1, 2, 3, 4, 5 };
List<int> lstProjectIds = context.Projects.Where(x => lstBizIds.Contains(x.businessId)).Select(x => x.projectId).ToList();

其次是:

List<int> lstBizIds = new List<int>() { 1, 2, 3, 4, 5 };
List<int> lstProjectIds = context.Projects.Join(lstBizIds, p => p.businessId, u => u, (p, u) => p.projectId).ToList();

现在我的问题是,上述哪种方法的性能更好?如果第一个列表(即 lstBizIds 的大小增加)也会影响性能吗?如果会降低性能,请向我建议其他实施方式。

【问题讨论】:

  • 您确定您的第一个选项有效吗?查询是否执行并给你一个结果?
  • 是的,肯定会奏效的。
  • 对不起,我的意思是第二个选项。无论如何,我假设你都成功地尝试了。
  • 与性能无关,但在两者之间做出决定时的另一个注意事项是,无论如何,在 EF Core 中,不同的连接器/提供程序在执行 Where INJOIN 时会以不同的方式转义字符.这个just bit me 带有用于 EF Core 的 Pomelo MySQL,但可以存在于我认为的任何提供程序中。

标签: c# sql-server entity-framework lambda linq-to-entities


【解决方案1】:

您应该使用Contains,因为 EF 可以产生更有效的查询。

这将是 SQL 连接:

SELECT Id
FROM Projects
INNER JOIN (VALUES (1), (2), (3), (4), (5)) AS Data(Item) ON Projects.UserId = Data.Item

这将是 SQL 包含:

SELECT Id
FROM Projects
WHERE UserId IN (1, 2, 3, 4, 5, 6)

INJOIN 更有效,因为 DBMS 可以停止查看IN 的第一个匹配项; JOIN 总是结束,即使在第一场比赛之后。

您可能还想检查实际发送到数据库的查询。您总是必须比较 SQL,而不是 LINQ 代码(显然)。

【讨论】:

  • 您对生成的 SQL 是正确的(尽管 SqlServer 的 join 看起来不同)+1。但不是哪个更有效 - 这实际上取决于数据库查询计划优化器。大多数现代查询优化器都会生成一个相同的执行计划。
  • 请注意,对于相对较大的集合(例如 > 1000 个项目),包含在实体框架中非常慢。由于内部原因,它很慢,而不是因为生成的查询很慢。因此,最好不要在大型​​集合上使用 Contains。
  • 相反,我最近做了一个比较 Contains 和 Join 的测试,Contains 在各方面都比 Join 好。 Contains 在查询执行方面比 Join 更快。而且在 SQL 生成方面也更快。使用 100K 项执行 Join 将在 SQL 生成期间给您一个 StackOverflow 异常。
  • 我决定使用 join 语法,因为它在代码中看起来更整洁,但我刚刚发现这是一个坏主意!生成的 SQL 很大(它为每个元素创建一个联合),并且当它比较的集合非常大时,实体框架在运行时完全失败。我花了很长时间才找到实时网站失败的原因。将连接替换为包含,现在一切正常
【解决方案2】:

执行联接非常有效,因为 Where 条件实际上执行了所有表的笛卡尔积,然后过滤满足条件的行。这意味着为每个行组合评估 Where 条件 (n1 * n2 * n3 * n4)

Join 运算符从第一个表中获取行,然后仅从第二个表中获取具有匹配键的行,然后仅从第三个表中获取具有匹配键的行,依此类推。其次, contains 将以迭代方式工作,使其比 join 慢

【讨论】:

  • 是的,我还在其中一个链接中发现了堆栈溢出:stackoverflow.com/questions/5551264/… 但在这里也找到了矛盾的解释:stackoverflow.com/questions/32650224/…
  • 这适用于 LINQ to Objects,但问题是关于 LINQ to Entities。
  • Join 方法在内部使用索引来连接两个结果集,但 where 使用了组合机制,使其速度变慢。 Join 快得多,因为它知道如何组合以将结果简化为相关组合。当您使用 Where 来指定关系时,它必须创建所有可能的组合,这最终会使其变慢。希望这能回答你的问题
  • 您可能遗漏了其中一方是数据库表而另一方是内存列表的部分。
【解决方案3】:


我选择第一个,因为它不会增加电脑的内存。
如果你使用两个数组来比较条件,从第二个中选择。

【讨论】:

    【解决方案4】:

    我只是花了一些时间试图找出导致程序中堆栈溢出错误的原因,该程序使用一些简单的 LINQ 查询访问中型数据库。

    对于一侧有约 10k 个元素的 ICollection,另一侧有 sql 表,从“join”到“Contains”的单个更改修复了堆栈溢出错误。

    看起来,尽管性能比较好,但 Contains 似乎是一个更安全的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-07
      • 2012-11-10
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多