在LINQ中,计数(count)和选择(select)哪个更快?

11

我在应用程序中使用IQueryable<T>接口,并延迟执行DB上的SQL直到像.ToList()这样的方法调用。

有时我需要查找某些列表的计数,而不需要使用被计数的列表中的数据。我知道从我的SQL经验来看,对于DB而言,SQL COUNT()比返回所有行的等效SELECT语句要少得多。

那么我的问题是:从IQueryable<T>Count()方法返回计数,在DB上是否工作量较小,而不是渲染IQueryable<T>为列表并调用列表的Count()方法?

我怀疑会,因为ToList()将触发SELECT SQL,然后在单独的查询中计算行数。我希望IQueryable<T>上的Count()仅将sql呈现为sql COUNT()查询。但我不确定。你知道吗?

3个回答

21

调用ToList()将返回一个包含所有数据的真正List<T>,这意味着需要获取所有数据。不太好。

调用Count()确实会在数据库端渲染SQL以进行计数。更好。

然而,检查最简单的方法是在数据上下文中启用日志记录(或者您特定提供者的等效方式),并查看实际发送了哪些查询。


1
Sql Server的COUNT仍然会很慢,因为它会导致表扫描! - Slaggg
1
@Slaggg,如果你有一个索引,它只会在你拥有的最小索引上进行索引扫描。如果你没有索引,它仍然会减少数据库服务器的网络负载(与返回所有行相比)。 - Albin Sunnanbo
@Albin - 你说得对。然而,索引本身仍然可能非常大。开发人员应该意识到COUNT并不是像他们期望的那样简单的操作。 - Slaggg
1
@Slaggg:请记住,OP已经声明:“我从我的SQL经验中知道,对于数据库来说,SQL COUNT()比返回所有行的等效SELECT语句要少得多。”虽然这可能并不是微不足道的,但我认为声称它会导致表扫描是误导性的。 - Jon Skeet
@Jon - 你说得对,我不应该说表扫描。话虽如此,问题是关于效率的。在数据库应用程序中,效率的一个主要关注点是最小化IO。开发人员应该意识到,为了理解COUNT的成本,需要找到最小索引(如果没有索引,则为表)的大小,并且所有这些数据都必须从磁盘读取(如果尚未缓存),同时表被锁定。我认为许多人认为COUNT像许多框架数据结构一样微不足道,只是一个简单的O(1)内存查找。但事实并非如此。这就是我的观点。 - Slaggg
显示剩余5条评论

-1

如果您正在使用SQL Server,Count()仍然非常昂贵,因为它会导致表扫描(或索引扫描,请参见主答案上的评论)。而且,默认情况下Linq不使用未提交的读取隔离级别,这会由于锁定而使情况变得更糟。

如果您可以接受结果是脏数据和总行数的近似值,则以下代码将比使用Count()快得多。根据我的经验,此代码返回的值很少与实际行数不同。

/// <summary>A very fast method for counting rows in a table.</summary>
public static long FastRowCount(DataContext context, string tableName)
{
    const string template = "SELECT rowcnt FROM sys.sysindexes WHERE id = OBJECT_ID('{0}') AND indid < 2";
    string query = string.Format(template, tableName);
    return context.ExecuteQuery<long>(query).Single();
}

可以合理地假设,在生产环境中,任何人都会对计数进行索引。 - John Shedletsky

-1
我不确定这是否是一个硬性规定,但你添加到IQueryable的linq方法将被添加到linq表达式树中 - 除非它们是那些实际上会导致树被评估的方法(如ToList和Single等)。 在LinqToSql的情况下,如果无法将某些内容转换为SQL语句,您将收到运行时异常,指出该方法不受支持。
例如:
var something = dbContext.SomeTable
  .Select(c => c.col1 == "foo")
  .Distinct()
  .ToList()
  .Count()

在上面的代码中,Select() 和 Distinct() 被包含在传递给服务器的 SQL 查询中,因为它们被添加到了一个 IQueryable 中。而 Count() 只是作用于由 SQL 查询返回的列表上。所以你不想这样做 :-)
在你的情况下,Count() 肯定比 Select() 更快,因为生成的 SQL 语句将确实包含计数,因此服务器只需要返回一个数字而不是一系列行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接