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

时间:2017-05-24 12:08:17

标签: sql sql-server count

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

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

2 个答案:

答案 0 :(得分:56)

不,COUNT(*)不是恒定时间操作。 COUNT(*)必须返回符合当前扫描谓词(即。WHERE子句)的行数,因此单独使元数据属性的返回无效。但即使你没有谓词,COUNT仍然必须满足当前的事务隔离语义,即。返回行可见的行数(例如,已提交)。因此,COUNT必须在SQL Server中实际扫描并计算行数。某些系统允许返回faster 'estimate' counts

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

  

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

这不是100%真实。至少有两种方案没有“加载整行”:

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

我上面说的大部分内容都不适用于Hekaton牌桌。

答案 1 :(得分:21)

  

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

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

  

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

我认为你高估了它的患病率。我不记得上次我关心单个表中的总行数与更多过滤后的视图或更复杂的连接操作中的计数。

这将是一个特别狭窄的优化,只能使单一查询风格受益,正如我所说,我认为你高估了它的发生频率。