【问题标题】:Performance of Any vs FirstOrDefaultAny 与 FirstOrDefault 的性能
【发布时间】:2013-01-28 22:58:34
【问题描述】:

所以我一直在挖掘 EF 为我们的应用程序生成的查询,我注意到Any 调用的一些奇怪的 sql 生成 - 它们似乎过于复杂。 Any 似乎会生成 case when (x) then 1 when (not x) then 0 end - 为什么不直接使用 else 呢?这样,在Any 应该返回false 的情况下,SQL 服务器必须执行两次相同的查询。我想出了在使用Where(cond).Select(q => true).FirstOrDefault() 的情况下似乎更快的解决方法,但我仍然对这是否只是疏忽还是有一些我遗漏的意义感兴趣。

context.Books.Any(b => b.Id == bookId);

declare @p__linq__0 Int = 1;

SELECT 
CASE WHEN ( EXISTS (SELECT 
    1 AS [C1]
    FROM [Books] AS [Extent1]
    WHERE [Extent1].[ID] = @p__linq__0
)) THEN cast(1 as bit) WHEN ( NOT EXISTS (SELECT 
    1 AS [C1]
    FROM [Books] AS [Extent2]
    WHERE [Extent2].[ID] = @p__linq__0
)) THEN cast(0 as bit) END AS [C1]
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]

context.Books.Where(b => b.ID == bookId).Select(b => true).FirstOrDefault();

declare @p__linq__0 Int = 1;

SELECT TOP (1) 
cast(1 as bit) AS [C1]
FROM [Books] AS [Extent1]
WHERE [Extent1].[ID] = @p__linq__0

【问题讨论】:

  • “这种方式 SQL 服务器必须执行两次相同的查询” - 这是一个假设。优化器可能能够发现正在执行相同的子查询 - 它不是相关的子查询,因此它实际上可能只执行一次。您需要使用分析器或获取执行计划才能确定(因此,一如既往,不要假设您知道哪里会出现性能问题 - 首先进行测量)。
  • @Damien_The_Unbeliever 对不起,我没有提到,但我确实检查了执行计划,当第一个条件不满足时,它确实再次执行给定的步骤。
  • 此处提供相同的 QA [StackOverFlow:LINQ Any 与 FirstOrDefault 的性能!= null][1] [1]:stackoverflow.com/questions/8339988/…

标签: sql-server entity-framework


【解决方案1】:

在您看到某物不存在之后,很明显它确实不存在,因此没有必要检查 agin 是否真的不存在。这只是 linq 产生过于复杂的查询的情况之一。您的解决方法有效,但它不一定像人们想要的那样容易理解,所以我建议在原始 linq 的性能方面受到影响,直到它真正成为性能问题。只需确保 Id 列上有索引即可。

【讨论】:

  • 我知道,在对索引进行简单查询的情况下,性能损失可以忽略不计,但相对而言,我们所说的执行时间要长 ±24%(在 5000000 次迭代的简单查询上测试),这是一个当您发现自己在可能需要数十毫秒甚至数百毫秒的更复杂查询上执行Any 时会遇到很多情况。
  • 如果这是性能问题,请务必使用您的解决方法。只需确保您注释代码为什么要按原样编写,这样下一个人就不会再次“清理”它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-11
  • 2013-04-12
  • 2019-09-16
  • 1970-01-01
  • 1970-01-01
  • 2013-09-03
相关资源
最近更新 更多