SQL count(*)性能

dan*_*iao 35 sql sql-server performance count

我有一个超过2000万行的SQL表BookChapters.它有一个集群主键(bookChapterID),没有任何其他键或索引.运行以下查询需要几毫秒

if (select count(*) from BookChapters) = 0
...
Run Code Online (Sandbox Code Playgroud)

但是,当我这样改变它需要10多分钟

if (select count(*) from BookChapters) = 1
...
Run Code Online (Sandbox Code Playgroud)

要么

if (select count(*) from BookChapters) > 1
...
Run Code Online (Sandbox Code Playgroud)

这是为什么?我怎样才能select count(*)更快地执行?

Ale*_*kov 53

Mikael Eriksson对第一个查询速度快的原因有一个很好的解释:

SQL服务器将其优化为: if exists(select * from BookChapters).因此,它寻找存在一行而不是计算表中的所有行.

对于其他两个查询,SQL Server将使用以下规则.要执行类似的查询SELECT COUNT(*),SQL Server将使用最窄的 非聚集索引来计算行数.如果表没有任何非聚集索引,则必须扫描该表.

此外,如果您的表具有聚集索引,您可以使用以下查询更快地获得计数(从此站点借用获取行计数快!)

--SQL Server 2005/2008
SELECT OBJECT_NAME(i.id) [Table_Name], i.rowcnt [Row_Count]
FROM sys.sysindexes i WITH (NOLOCK)
WHERE i.indid in (0,1)
ORDER BY i.rowcnt desc

--SQL Server 2000
SELECT OBJECT_NAME(i.id) [Table_Name], i.rows [Row_Count]
FROM sysindexes i (NOLOCK)
WHERE i.indid in (0,1)
ORDER BY i.rows desc
Run Code Online (Sandbox Code Playgroud)

它使用sysindexes系统表.您可以在此处找到更多信息SQL Server 2000,SQL Server 2005,SQL Server 2008,SQL Server 2012

这是另一个链接为什么我的SELECT COUNT(*)运行如此之慢?与另一种解决方案 它显示了当您右键单击表并选择属性时Microsoft用于快速显示行数的技术.

select sum (spart.rows)
from sys.partitions spart
where spart.object_id = object_id(’YourTable’)
and spart.index_id < 2
Run Code Online (Sandbox Code Playgroud)

你会发现无论你有多少桌子,这都会很快恢复.

如果您仍在使用SQL 2000,则可以使用sysindexes表来获取数字.

select max(ROWS)
from sysindexes
where id = object_id(’YourTable’)
Run Code Online (Sandbox Code Playgroud)

这个数字可能略有偏差,具体取决于SQL更新sysindexes表的频率,但它通常是相同的(或者至少足够接近).


ehs*_*net 12

如果您只想知道行数,请尝试此操作:

exec sp_spaceused [TABLE_NAME]
Run Code Online (Sandbox Code Playgroud)


Mik*_*son 7

如果您查看查询的执行计划,您将看到正在发生的事情.

if (select count(*) from BookChapters) = 0查询优化器将您的第一个查询识别为与查询优化器相同if exists(select * from BookChapters).如果存在至少一行,则SQL Server知道表达式为true,因此它会查找是否存在一行而不是计算表中的所有行.

对于您的其他查询,它不能那么聪明,并且必须先计算表中的行数,然后才能确定表达式的计算结果是true还是false.


EL *_*bov 5

你考虑过查询select count(BookChapterId) from BookChapterTable 吗?- 其中`BookChapterId 是非聚集索引.这应该使它运行得更快.

根据表如何使用和行访问,查询对非聚集索引可能是关键的一点:我只是把一些点从MDSN:

  • 在创建非聚簇索引之前,请了解如何访问数据.考虑使用非聚簇索引:
  • 包含大量不同的值,诸如列
    姓和名称(如果是聚簇索引被用于其他列)的组合.如果有极少数不同的值,如
    只有1和0,因为表的大多数查询不会使用索引
    扫描通常更加有效.
  • 不返回大型结果集的查询.
  • 经常涉及
    返回完全匹配的查询(WHERE 子句)的搜索条件的列.
  • 经常需要加入和分组的决策支持系统应用程序.在连接和分组操作中涉及的列上创建多个非聚簇索引,并在任何外键列上创建聚簇索引.
  • 覆盖给定查询中一个表的所有列.这样就完全无法访问表或聚簇索引.