SQL Server中的COUNT(*)是一个恒定时间操作吗?如果没有,为什么不呢?

dot*_*NET 36 sql sql-server count

我正在另一篇文章中阅读此讨论,其中有人提出这个问题.在阅读讨论之前,我一直认为SQL Server(和其他DBMS)在元数据中的某个位置保留了每个表的全局行数,但讨论似乎并非如此.为什么?Count(*)(没有任何过滤)如果是O(1),那么这种常见的操作会得到巨大的提升.即使不考虑COUNT(*),表中的总行数也是如此基本的信息.他们为什么不记下它呢?

另外,为什么我们需要"加载"整行(如我链接的帖子中所示)只是为了计算它们?索引或PK等不足以统计它们吗?

Rem*_*anu 56

不,COUNT(*)不是一个恒定的时间操作.一个COUNT(*)必须返回符合当前扫描谓语(即行数WHERE条),让独自会使元数据属性无效的回报.但即使你没有谓词,COUNT仍然必须满足当前的事务隔离语义,即.返回可见行数(例如,已提交).因此,COUNT必须在SQL Server中实际扫描并计算行数.一些系统允许返回更快的"估计"计数.

此外,作为一个边评论,依托rowssys.partitions是不可靠的.毕竟,如果这个计数能保证准确,那么我们就不需要了DBCC UPDATEUSAGE(...) WITH COUNT_ROWS.有几种情况在历史上会导致这个计数器偏离现实(主要是最低限度记录的插入回滚),我所知道的都是固定的,但仍然存在以下问题:1)从早期版本升级的表有错误和2 )其他,尚未发现,错误.

另外,为什么我们需要"加载"整行(如我链接的帖子中所示)只是为了计算它们?索引或PK等不足以统计它们吗?

这不是100%的真实.至少有两种方案没有"加载整行":

  • 窄行存储索引只加载'index'行,这可能要小得多
  • columnstore数据仅加载相关的列段

我上面说的大部分内容都不适用于Hekaton表.


Dam*_*ver 21

为什么我们需要"加载"整行

我们没有.SQL Server倾向于使用可以满足查询的最小索引.

Count(*) (没有任何过滤)是这样一种常见的操作

我认为你高估了它的流行程度.我不记得上次我关心单个表中的总行数与更过滤的视图或更复杂的连接操作的计数.

这将是一个非常狭窄的优化,只能使单一查询风格受益,而且正如我所说,我认为你已经高估了它的发生频率.

  • 对所有行进行计数的一种情况是常见的,值得优化的是使用表来实现队列时,需要经常监视其大小.当然,使用表格作为队列还有许多其他问题和警告,但我只想指出它.请注意,即使使用Service Broker(特别是吹捧在SQL Server中实现队列的好方法),队列上的`COUNT(*)`也会像常规表一样减慢行数,因此使用`COUNT(*)`的快速近似之一非常值得. (3认同)