在SQL Server中COUNT(*)是一个常量操作吗? 如果没有,为什么不呢?

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

此外,为什么我们需要“加载”整个行(如链接后的post所示)来计算它们呢? 不应该索引或PK等足以数它们?

不, COUNT(*)不是一个固定的时间操作。 COUNT(*)必须返回符合当前扫描谓词(即WHERE子句)的行的计数,以便单独使元数据属性返回无效。 但即使你没有谓词,COUNT仍然必须满足当前的事务隔离语义,即。 返回可见的行数(例如提交)。 因此, COUNT必须,并且将在SQL Server中实际扫描和计数行。 一些系统允许返回更快的“估计”计数 。

另外,作为一个方面的评论,依靠sys.partitions中的rows是不可靠的。 毕竟,如果这个计数将被保证准确,那么我们不需要DBCC UPDATEUSAGE(...) WITH COUNT_ROWS 。 历史上有几种情况会导致这个计数器偏离现实(主要是最小化日志logging的插入回滚),我所知道的都是固定的,但是这仍然留下以下问题:1)来自早期版本的具有错误和2 )其他,还没有发现,错误。

此外,为什么我们需要“加载”整个行(如链接后的post所示)来计算它们呢? 不应该索引或PK等足以数它们?

这不是100%真实的。 至less有两种情况不会“加载整行”:

  • 狭窄的行存储索引加载只是“索引”行,可能会小得多
  • 列存储数据只加载相关的列段

而我上面说的大部分都不适用于Hekaton表。

为什么我们需要“加载”整个行

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

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

我认为你高估了它的stream行。 我不记得上一次我关心单个表中的总行数与更复杂的联合操作中的更多过滤视图或计数。

这将是一个非常狭窄的优化,只能有利于单一风格的查询,正如我所说,我认为你高估了它发生的频率。