Linq To Entities - 任何VS First VS存在

Mig*_*ura 15 entity-framework exists any ef-code-first

我正在使用实体框架,我需要检查名称="xyz"的产品是否存在...

我想我可以使用Any(),Exists()或First().

对于这种情况,哪一个是最好的选择?哪一个性能最好?

谢谢,

米格尔

Str*_*ior 29

好吧,我不打算对此进行评估,但迭戈的答案使事情变得复杂,我认为还有一些额外的解释.

在大多数情况下,.Any()会更快.这里有些例子.

Workflows.Where(w => w.Activities.Any())
Workflows.Where(w => w.Activities.Any(a => a.Title == "xyz"))
Run Code Online (Sandbox Code Playgroud)

在上面的两个示例中,Entity Framework生成最佳查询.该.Any()调用是谓词的一部分,实体框架可以很好地处理这个问题.但是,如果我们.Any()将结果集的部分结果如下:

Workflows.Select(w => w.Activities.Any(a => a.Title == "xyz"))
Run Code Online (Sandbox Code Playgroud)

...突然实体框架决定创建条件的两个版本,因此查询的确需要两倍于它真正需要的工作.但是,以下查询不是更好:

Workflows.Select(w => w.Activities.Count(a => a.Title == "xyz") > 0)
Run Code Online (Sandbox Code Playgroud)

鉴于上述查询,Entity Framework仍将创建该条件的两个版本,此外它还需要SQL Server进行实际计数,这意味着它一旦找到项目就不会发生短路.

但是,如果您只是比较这两个查询:

  1. Activities.Any(a => a.Title == "xyz")
  2. Activities.Count(a => a.Title == "xyz") > 0

......哪个会更快?这取决于.

第一个查询产生一个低效的双条件查询,这意味着它将花费最多两倍的时间.

第二个查询强制数据库检查表中的每个项目而不会发生短路,这意味着它可能需要的N时间长于必须的时间,具体取决于在找到匹配项之前需要评估的项目数.我们假设该表有10,000个项目:

  • 如果表中的项目与条件不匹配,则此查询将花费大约一半的时间作为第一个查询.
  • 如果表中的第一项与条件匹配,则此查询将比第一个查询长约5,000倍.
  • 如果表中的一个项是匹配项,则此查询的平均时间将比第一个查询长2,500倍.
  • 如果查询能够利用Title和键列上的索引,则此查询将花费大约一半的时间作为第一个查询.

总而言之,如果你是:

  1. 使用Entity Framework 4(因为较新的版本可能会改进查询结构) Entity Framework 6.1或更早版本(因为6.1.1有修复来改进查询),AND
  2. 直接查询表(而不是执行子查询),AND
  3. 直接使用结果(而不是它是谓词的一部分),AND
  4. 或者:
    1. 您在要查询的表上设置了良好的索引,或者
    2. 您希望大部分时间都找不到该项目

那么你可以期待.Any()多达两倍的时间.Count().例如,查询可能需要100毫秒而不是50或10而不是5.

在任何其他情况下, .Any()应该至少同样快,并且可能比数量快几个数量级.Count().

无论如何,在您确定这实际上是产品性能不佳的根源之前,您应该更关心什么是易于理解的..Any()更清楚,更简洁地陈述你真正想要弄清楚的东西,所以坚持下去.

  • "除非您确定这实际上是产品性能不佳的原因,否则您应该更加关注易于理解的内容." 评论 (4认同)

Jim*_*ley 24

任何转换为​​数据库级别的"存在".首先转换为Select Top 1 ...在这些之间,Exists将执行First,因为不需要获取实际对象,只需要布尔结果值.

至少你没有询问.Where(x => x.Count()> 0)这需要对整个匹配集进行评估和迭代,然后才能确定你有一条记录.任何短路请求都会明显加快.

  • +1.澄清一下:计算整个匹配集是在数据库级别完成的,因此它不会将对象提取到您的应用程序中.仍然`.Any()`更简单,它将胜过`.Where(x => x.Count> 0)`,因此它应该是首选. (3认同)