在系统中。Linq命名空间,我们现在可以扩展我们的IEnumerable来拥有Any()和Count()扩展方法。
最近有人告诉我,如果我想检查一个集合中是否包含1个或多个项目,我应该使用. any()扩展方法而不是. count() > 0扩展方法,因为. count()扩展方法必须遍历所有项目。
其次,一些集合具有Count或Length属性(而不是扩展方法)。使用这些,而不是.Any()或.Count()会更好吗?
-是的-不?
在系统中。Linq命名空间,我们现在可以扩展我们的IEnumerable来拥有Any()和Count()扩展方法。
最近有人告诉我,如果我想检查一个集合中是否包含1个或多个项目,我应该使用. any()扩展方法而不是. count() > 0扩展方法,因为. count()扩展方法必须遍历所有项目。
其次,一些集合具有Count或Length属性(而不是扩展方法)。使用这些,而不是.Any()或.Count()会更好吗?
-是的-不?
当前回答
编辑:在EF 6.1.1版本中修复。这个答案是不实际的
对于SQL Server和EF4-6, Count()的执行速度比Any()快两倍。
当你运行Table.Any()时,它会生成类似这样的东西(警告:不要伤害大脑试图理解它)
SELECT
CASE WHEN ( EXISTS (SELECT
1 AS [C1]
FROM [Table] AS [Extent1]
)) THEN cast(1 as bit) WHEN ( NOT EXISTS (SELECT
1 AS [C1]
FROM [Table] AS [Extent2]
)) THEN cast(0 as bit) END AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
这需要对符合条件的行进行两次扫描。
我不喜欢写Count() > 0,因为它隐藏了我的意图。我更喜欢使用自定义谓词:
public static class QueryExtensions
{
public static bool Exists<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
{
return source.Count(predicate) > 0;
}
}
其他回答
由于这是一个相当流行的话题,答案各不相同,我不得不重新审视这个问题。
测试env: EF 6.1.3, SQL Server, 300k记录
表模型:
class TestTable
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
测试代码:
class Program
{
static void Main()
{
using (var context = new TestContext())
{
context.Database.Log = Console.WriteLine;
context.TestTables.Where(x => x.Surname.Contains("Surname")).Any(x => x.Id > 1000);
context.TestTables.Where(x => x.Surname.Contains("Surname") && x.Name.Contains("Name")).Any(x => x.Id > 1000);
context.TestTables.Where(x => x.Surname.Contains("Surname")).Count(x => x.Id > 1000);
context.TestTables.Where(x => x.Surname.Contains("Surname") && x.Name.Contains("Name")).Count(x => x.Id > 1000);
Console.ReadLine();
}
}
}
结果:
Any() ~ 3ms
Count()第一次查询~ 230ms,第二次查询~ 400ms
备注:
对于我的案例,EF没有像@Ben在他的帖子中提到的那样生成SQL。
我已经使用IList创建了一个示例应用程序,其中包含100个元素到100万个项目,以查看Count vs Any哪个是最好的。
Code
class Program
{
static void Main()
{
//Creating List of customers
IList<Customer> customers = new List<Customer>();
for (int i = 0; i <= 100; i++)
{
Customer customer = new Customer
{
CustomerId = i,
CustomerName = string.Format("Customer{0}", i)
};
customers.Add(customer);
}
//Measuring time with count
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
if (customers.Count > 0)
{
Console.WriteLine("Customer list is not empty with count");
}
stopWatch.Stop();
Console.WriteLine("Time consumed with count: {0}", stopWatch.Elapsed);
//Measuring time with any
stopWatch.Restart();
if (customers.Any())
{
Console.WriteLine("Customer list is not empty with any");
}
stopWatch.Stop();
Console.WriteLine("Time consumed with count: {0}", stopWatch.Elapsed);
Console.ReadLine();
}
}
public class Customer
{
public int CustomerId { get; set; }
public string CustomerName { get; set; }
}
结果:
任何都比数好。
关于Count()方法,如果IEnumerable是一个ICollection,那么我们不能遍历所有的项目,因为我们可以检索ICollection的Count字段,如果IEnumerable不是一个ICollection,我们必须使用一个MoveNext while遍历所有的项目,看看。net框架代码:
public static int Count<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
throw Error.ArgumentNull("source");
ICollection<TSource> collectionoft = source as ICollection<TSource>;
if (collectionoft != null)
return collectionoft.Count;
ICollection collection = source as ICollection;
if (collection != null)
return collection.Count;
int count = 0;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
checked
{
while (e.MoveNext()) count++;
}
}
return count;
}
参考:可枚举的参考源
如果您正在使用实体框架,并且有一个包含许多记录的巨大表,Any()将会更快。我记得有一次,我想检查一个有数百万行的表是否为空。Count() > 0完成耗时20-30秒。Any()是即时的。
Any()可以提高性能,因为它可能不必迭代集合来获得事物的数量。只要击中其中一个就行。或者,对于LINQ-to-Entities,生成的SQL将是IF EXISTS(…)而不是SELECT COUNT…甚至选择* ....
这取决于数据集有多大,以及您的性能要求是什么?
如果不是很大,就用最易读的形式, 这对我来说是任何,因为它比方程更短更易读。