一尘不染

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

sql

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

另外,为什么我们需要“装载”整行(如我链接的文章中所述)只是为了对它们进行计数?索引或PK等不应该足以计算它们吗?


阅读 127

收藏
2021-03-17

共1个答案

一尘不染

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

另外,作为附带说明,依靠rowsinsys.partitions是不可靠的。毕竟,如果可以保证此计数是准确的,那么我们将不需要DBCC UPDATEUSAGE(...) WITH COUNT_ROWS。从历史上看,有几种情况会导致此计数器偏离实际情况(大多数情况下日志记录的插入回滚最少),我所知道的都是固定的,但仍然存在以下问题:1)包含错误的早期版本的升级表和2
)其他尚未发现的错误。

另外,为什么我们需要“装载”整行(如我链接的文章中所述)只是为了对它们进行计数?索引或PK等不应该足以计算它们吗?

这不是100%正确。至少有两种情况不“加载整行”:

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

而且我上面所说的大多数内容都不适用于Hekaton表格。

2021-03-17