为了账号安全,请及时绑定邮箱和手机立即绑定

哪种方法执行得更好:.Any()vs.Count()>0?

哪种方法执行得更好:.Any()vs.Count()>0?

撒科打诨 2019-06-24 15:27:40
哪种方法执行得更好:.Any()vs.Count()>0?在System.Linq命名空间,我们现在可以扩展IEnumerable就是拥有Any()和Count() 可拓方法.最近有人告诉我,如果我想检查一个集合中包含一个或多个项目,我应该使用.Any()扩展方法,而不是.Count() > 0方法,因为.Count()扩展方法必须遍历所有项。第二,一些集合有一个财产(不是扩展方法)Count或Length..是否最好使用这些,而不是.Any()或.Count() ?是吗?
查看完整描述

3 回答

?
呼如林

TA贡献1798条经验 获得超3个赞

如果您是从具有.Length.Count(如ICollection<T>IList<T>List<T>,等等)-那么这将是最快的选择,因为它不需要通过GetEnumerator()/MoveNext()/Dispose()所需序列Any()检查是否为非空的IEnumerable<T>顺序。

只为IEnumerable<T>,然后Any()将要一般要更快,因为它只需要看一次迭代。但是,请注意,Count()检查ICollection<T>(使用.Count作为一种优化)-如果您的底层数据源是直接一个清单/集合,不会有太大的差别。别问我为什么它不使用非通用的ICollection...

当然,如果您使用LINQ来过滤它,等等(Where(等等),您将有一个基于迭代器块的序列,因此ICollection<T>优化是无用的。

一般IEnumerable<T>*坚持Any();-p


查看完整回答
反对 回复 2019-06-24
?
喵喔喔

TA贡献1735条经验 获得超5个赞

当实体框架4是实际的时候,我写了这个答案。这个答案的目的不在于涉及琐碎的问题。.Any()VS.Count()性能测试。关键是要表明EF远非十全十美。新版本更好.。但是,如果您的代码部分速度慢,并且使用EF,则使用直接TSQL进行测试,并比较性能,而不是依赖于假设(即.Any()总是比.Count() > 0).


虽然我同意大多数人投票通过的回答和评论-特别是在这一点上Any信号开发意图Count() > 0-在SQLServer(EntityFramework4)上,计数按数量级计算得更快。

下面是查询Any超时异常(在~200.000条记录上):

con = db.Contacts.
    Where(a => a.CompanyId == companyId && a.ContactStatusId <= (int) Const.ContactStatusEnum.Reactivated
        && !a.NewsletterLogs.Any(b => b.NewsletterLogTypeId == (int) Const.NewsletterLogTypeEnum.Unsubscr)
    ).OrderBy(a => a.ContactId).
    Skip(position - 1).
    Take(1).FirstOrDefault();

Count版本以毫秒为单位执行:

con = db.Contacts.
    Where(a => a.CompanyId == companyId && a.ContactStatusId <= (int) Const.ContactStatusEnum.Reactivated
        && a.NewsletterLogs.Count(b => b.NewsletterLogTypeId == (int) Const.NewsletterLogTypeEnum.Unsubscr) == 0
    ).OrderBy(a => a.ContactId).
    Skip(position - 1).
    Take(1).FirstOrDefault();

我需要找到一种方法来查看两个LINQ所产生的确切SQL-但很明显,两者之间的性能差别很大。CountAny在某些情况下,不幸的是,你似乎不能就这样Any在任何情况下。

编辑:这里是生成的SQL。如你所见;)

ANY:

exec sp_executesql N'SELECT TOP (1) 
[Project2].[ContactId] AS [ContactId], 
[Project2].[CompanyId] AS [CompanyId], 
[Project2].[ContactName] AS [ContactName], 
[Project2].[FullName] AS [FullName], 
[Project2].[ContactStatusId] AS [ContactStatusId], 
[Project2].[Created] AS [Created]
FROM ( SELECT [Project2].[ContactId] AS [ContactId], [Project2].[CompanyId] AS [CompanyId], [Project2].[ContactName] AS [ContactName],
 [Project2].[FullName] AS [FullName], [Project2].[ContactStatusId] AS [ContactStatusId], [Project2].[Created] AS [Created], row_number() 
 OVER (ORDER BY [Project2].[ContactId] ASC) AS [row_number]
    FROM ( SELECT 
        [Extent1].[ContactId] AS [ContactId], 
        [Extent1].[CompanyId] AS [CompanyId], 
        [Extent1].[ContactName] AS [ContactName], 
        [Extent1].[FullName] AS [FullName], 
        [Extent1].[ContactStatusId] AS [ContactStatusId], 
        [Extent1].[Created] AS [Created]
        FROM [dbo].[Contact] AS [Extent1]
        WHERE ([Extent1].[CompanyId] = @p__linq__0) AND ([Extent1].[ContactStatusId] <= 3) AND ( NOT EXISTS (SELECT 
            1 AS [C1]
            FROM [dbo].[NewsletterLog] AS [Extent2]
            WHERE ([Extent1].[ContactId] = [Extent2].[ContactId]) AND (6 = [Extent2].[NewsletterLogTypeId])
        ))
    )  AS [Project2]
)  AS [Project2]
WHERE [Project2].[row_number] > 99
ORDER BY [Project2].[ContactId] ASC',N'@p__linq__0 int',@p__linq__0=4

COUNT:

exec sp_executesql N'SELECT TOP (1) 
[Project2].[ContactId] AS [ContactId], 
[Project2].[CompanyId] AS [CompanyId], 
[Project2].[ContactName] AS [ContactName], 
[Project2].[FullName] AS [FullName], 
[Project2].[ContactStatusId] AS [ContactStatusId], 
[Project2].[Created] AS [Created]
FROM ( SELECT [Project2].[ContactId] AS [ContactId], [Project2].[CompanyId] AS [CompanyId], [Project2].[ContactName] AS [ContactName],
 [Project2].[FullName] AS [FullName], [Project2].[ContactStatusId] AS [ContactStatusId], [Project2].[Created] AS [Created],
  row_number() OVER (ORDER BY [Project2].[ContactId] ASC) AS [row_number]
    FROM ( SELECT 
        [Project1].[ContactId] AS [ContactId], 
        [Project1].[CompanyId] AS [CompanyId], 
        [Project1].[ContactName] AS [ContactName], 
        [Project1].[FullName] AS [FullName], 
        [Project1].[ContactStatusId] AS [ContactStatusId], 
        [Project1].[Created] AS [Created]
        FROM ( SELECT 
            [Extent1].[ContactId] AS [ContactId], 
            [Extent1].[CompanyId] AS [CompanyId], 
            [Extent1].[ContactName] AS [ContactName], 
            [Extent1].[FullName] AS [FullName], 
            [Extent1].[ContactStatusId] AS [ContactStatusId], 
            [Extent1].[Created] AS [Created], 
            (SELECT 
                COUNT(1) AS [A1]
                FROM [dbo].[NewsletterLog] AS [Extent2]
                WHERE ([Extent1].[ContactId] = [Extent2].[ContactId]) AND (6 = [Extent2].[NewsletterLogTypeId])) AS [C1]
            FROM [dbo].[Contact] AS [Extent1]
        )  AS [Project1]
        WHERE ([Project1].[CompanyId] = @p__linq__0) AND ([Project1].[ContactStatusId] <= 3) AND (0 = [Project1].[C1])
    )  AS [Project2]
)  AS [Project2]
WHERE [Project2].[row_number] > 99
ORDER BY [Project2].[ContactId] ASC',N'@p__linq__0 int',@p__linq__0=4

似乎纯粹的Where With比计算Count然后使用count=0执行WHERE要糟糕得多。

如果你们看到我的发现有什么错误请告诉我。不管对VS计数的讨论如何,都可以从这一切中删除任何更复杂的LINQ,当将其重写为存储过程时,情况要好得多;)。


查看完整回答
反对 回复 2019-06-24
  • 3 回答
  • 0 关注
  • 892 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信